使用 $in 运算符对大量 ID 进行 id 查询的 Mongodb 太慢了,有其他选择吗?

标签 mongodb mongodb-query spring-data-mongodb

我正在开发一个项目,该项目使用 Solr 进行全文搜索并使用 Mongodb 作为持久存储。基本上,在 Solr 中搜索会返回 Mongo id,然后我们使用这些 id 来获取文档。

问题在于某些 Solr 搜索按数千个 ID 的顺序返回结果。这些结果实际上是我们所期望的,所以这里的 Solr 没有问题。当我们想从 mongodb 中获取 10k ID 时,问题就来了。查询正在使用 $in 但花费的时间太长;检查mongodb profiler后,mongo似乎花了很多时间等待获取读锁。

还有其他方法吗?也许仍然使用 $in 但将 ID 集拆分成更小的 block ?

附带说明一下,我们使用的是 Java 8,以及 Spring 4.0 和 Spring-Data-Mongo 1.6

此外,作为附加信息,该集合有 130 万个文档,每个文档的平均大小为 11Kb。

这里是一个查询的例子:

  {"_id" : {
        "$in" : [
            ObjectId("5441614a5d28a9872823694c"),
            ObjectId("544155eb5d28a987281aa112"),
            ObjectId("5441500e5d28a9872815b917"),
            ObjectId("544153285d28a987281877b9"),
            ObjectId("544159095d28a987281c1f5c"),
            ObjectId("54415b105d28a987281d3ad7"),
            ObjectId("54415a995d28a987281cf0e6"),
            ObjectId("544160215d28a9872822383b"),
            ObjectId("544160e85d28a98728230342"),
            ObjectId("544157ba5d28a987281b7dea"),
            ObjectId("54415e375d28a9872820508b"),
            ObjectId("544150f75d28a98728169563"),
            ObjectId("54415c6b5d28a987281e8bcb"),
            ObjectId("54415a6d5d28a987281cd704").............]}}

这是一个小集合的解释结果:

{
"cursor" : "BtreeCursor _id_ multi",
"isMultiKey" : false,
"n" : 14,
"nscannedObjects" : 14,
"nscanned" : 27,
"nscannedObjectsAllPlans" : 14,
"nscannedAllPlans" : 27,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
    "_id" : [
        [
            ObjectId("5441500e5d28a9872815b917"),
            ObjectId("5441500e5d28a9872815b917")
        ],
        [
            ObjectId("544150f75d28a98728169563"),
            ObjectId("544150f75d28a98728169563")
        ],
        [
            ObjectId("544153285d28a987281877b9"),
            ObjectId("544153285d28a987281877b9")
        ],
        [
            ObjectId("544155eb5d28a987281aa112"),
            ObjectId("544155eb5d28a987281aa112")
        ],
        [
            ObjectId("544157ba5d28a987281b7dea"),
            ObjectId("544157ba5d28a987281b7dea")
        ],
        [
            ObjectId("544159095d28a987281c1f5c"),
            ObjectId("544159095d28a987281c1f5c")
        ],
        [
            ObjectId("54415a6d5d28a987281cd704"),
            ObjectId("54415a6d5d28a987281cd704")
        ],
        [
            ObjectId("54415a995d28a987281cf0e6"),
            ObjectId("54415a995d28a987281cf0e6")
        ],
        [
            ObjectId("54415b105d28a987281d3ad7"),
            ObjectId("54415b105d28a987281d3ad7")
        ],
        [
            ObjectId("54415c6b5d28a987281e8bcb"),
            ObjectId("54415c6b5d28a987281e8bcb")
        ],
        [
            ObjectId("54415e375d28a9872820508b"),
            ObjectId("54415e375d28a9872820508b")
        ],
        [
            ObjectId("544160215d28a9872822383b"),
            ObjectId("544160215d28a9872822383b")
        ],
        [
            ObjectId("544160e85d28a98728230342"),
            ObjectId("544160e85d28a98728230342")
        ],
        [
            ObjectId("5441614a5d28a9872823694c"),
            ObjectId("5441614a5d28a9872823694c")
        ]
    ]
},
"server" : "0001a22df018:27017"

最佳答案

也许这些信息可以提供帮助,仅供引用。

集合的大小大于 1.3M x 11K = 14.6GB(不小)
你要查询的文档的比率是10K/1.3M = 0.75%

文档已编入索引,找到任何一个都应该非常快。但是收藏量很大。由于您没有提供有关 ID 的信息,因此我只是假设这些 ID 的文档分布几乎是任意的。
首先,MongoDB 可能会尝试从内存中查找所有文档。当再也找不到时,它会根据剩余的id从磁盘中加载新数据到内存中,并再次重复查找,直到最后完成工作。从磁盘加载的时间可能是决定查询性能的主要因素。加载时间取决于您的 ID 分布。如果它们分布非常密集,查询应该非常快,否则可能会变慢。因此,速度取决于您正在搜索的文档的分布情况。

使用分片集合(更多分片实例)可能会有所帮助。

关于使用 $in 运算符对大量 ID 进行 id 查询的 Mongodb 太慢了,有其他选择吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26659447/

相关文章:

java - Spring数据mongodb审计不起作用..(Java配置)

node.js - MongoDB 过滤器 $lookup 具有日期范围的文档

mongodb - 如何选择值高于平均值的文档

java - 将通用对象与 Spring Data Mongo 一起使用

node.js - 对象数组中的 MongoDB,仅显示具有指定值的对象

arrays - 避免 mongodb 中的空数组元素

java - 枚举作为带有 DBref 和 spring data mongo 的 Map 的键

node.js - 我正在使用 express js、mongoose 和 ember js。有没有办法只写一次模型?

node.js - Mongoose - find({},cb) 和 find({}).exec(cb) 之间有什么区别?

javascript - 我如何使用 Mongoose 确定用户是否喜欢帖子