MongoDB第一次读取后的慢速读取

MongoDB第一次读取后的慢速读取,mongodb,mongodb-query,Mongodb,Mongodb Query,我需要查询大量文档(>100M),并且我正在批量请求5000个文档(每个文档约4-5MB)。 由于某种原因,第一个请求(没有\u id过滤)会快速返回(~1.5s),而 休息需要相当长的时间(~8-9.5秒) 现在,当批量读取500个文档(每个文档约500kB)时,时间安排明显更好(~0.5-0.8s),并且对于每个请求都是一致的 我正在使用\u id+limit分页方式,因为我看到skip+limit方法的性能要差得多 这是我的流程示例 var mongodb = require("mongo

我需要查询大量文档(>100M),并且我正在批量请求5000个文档(每个文档约4-5MB)。 由于某种原因,第一个请求(没有
\u id
过滤)会快速返回(~1.5s),而 休息需要相当长的时间(~8-9.5秒)

现在,当批量读取500个文档(每个文档约500kB)时,时间安排明显更好(~0.5-0.8s),并且对于每个请求都是一致的

我正在使用
\u id+limit
分页方式,因为我看到
skip+limit
方法的性能要差得多

这是我的流程示例

var mongodb = require("mongodb")
var bytes = require("bytes")

...

var filter = {
    '_id': { '$gt': this._lastId }
}

if(mongodb.ObjectId.isValid(this._lastId)) {
    filter['_id'] = { '$gt': this._lastId }
}

var cursor = this.conn.collection(collectionName)
    .find(filter)
    .limit(5000)

var start = new Date().getTime()
cursor.toArray(function(err, docs) {
    if (err) { ... }

    var elapsed = (new Date().getTime() - start) / 1000

    console.log(
        "Docs:", docs.length,
        "Size:", bytes(sizeof(docs)),
        "Took:", elapsed + " seconds"
    )

    var lastDoc = docs[docs.length - 1]

    this._lastId = lastDoc._id
})

...

我发现这个问题很有趣,试着重现它,得到了相同的结果:从id 0到5000的第一个调用速度很快,而所有其他调用的时间都很长(大约7倍)

这与不带过滤器的读取有关。如果在mongo shell中运行命令并对查找结果进行解释,您将看到在从0读取到5000时没有应用任何筛选器

您可以使用一次获取更多文档(根据您的数据,每个文档大约1KB)。默认值为每次游标迭代20次。 当您运行.toArray()函数时,它将从MongoDB向您的应用程序发送20KB的数据块,直到5000个文档被传输为止。使用更大的批处理可能更为优化,您应该尝试不同的值,但我会从500开始,一次获得500KB,因为它减少了小数据块的网络开销。 您还可能会发现这样做效果更好,因为它在处理数据时(通过batchSize(n)的块)传输数据。在这种情况下,如果查询整个集合或5000个块(如果最后要检查所有文档),则没有多大关系

游标使连接保持打开状态,并在MongoDB服务器上分配资源,直到您关闭游标或与DB的连接,但游标的大小不会增加—它只保存批处理的数据


另一方面,我认为做小批量并不是更快:每个文档的时间是相似的,少10倍的文档大约快10倍。

我意识到小批量也一样,但小批量可能会更好地使用系统内存。你能详细说明一下cursor.batchSize()的用法吗?我对它不太熟悉。它会保持一个开放的连接,直到它耗尽,对吗?对于100多万个可能需要花费大量时间的文档,批量大小在250到500之间将为您提供最佳结果。批量5000太多,MongoDB驱动程序会在内部将其分解为最大1000的大小。