【问题标题】:removing "scanAndOrder" : true in my MongoDB query result删除“scanAndOrder”:在我的 MongoDB 查询结果中为 true
【发布时间】:2012-08-08 18:51:18
【问题描述】:

所以我在我的数据库中有一个包含以下 shardkey 的集合:{cl:"yyyy-mm", user_id:N}

当我执行后续查询时

db.collection.find({ cl:"2012-03", user_id:{$in:users}, _id:{"$lt":new ObjectId('4f788b54204cfa4946000044')} }).sort({_id:-1}).limit(5).explain(true)

它给了我这个结果:

"clusteredType" : "ParallelSort",
"shards" : {
    "set1/hostname.com:27018" : [
        {
            "cursor" : "BtreeCursor cl_1_user_id_1 multi",
            "nscanned" : 21294,
            "nscannedObjects" : 21288,
            "n" : 5,
            "scanAndOrder" : true,
            "millis" : 1258,
            "nYields" : 69,
            "nChunkSkips" : 0,
            "isMultiKey" : false,
            "indexOnly" : false,
            "indexBounds" : { ...

那么如何进行排序以使用索引然后我不需要扫描所有 21288 个文档,只需返回最后 5 个?

【问题讨论】:

  • 您使用的是哪个版本的 MongoDB?由于以下原因,您可能会发现 2.2.0-rc0 在此查询上做得更好:jira.mongodb.org/browse/SERVER-5063
  • $in 的“用户”示例值是多少?如果只搜索一个user_id,你能发布一个解释的结果吗?

标签: mongodb sorting indexing sharding


【解决方案1】:

感谢您对 Dex 的大力支持!

如果在 2013 年还不算太晚,我推荐的避免 scanAndOrder 的索引是 { _id: -1, cl: 1, user_id: 1 }。

原因是因为 _id 上的 $lt 和 user_id 上的 $in 构成了跨多个索引“桶”的范围。除上述顺序之外的任何其他顺序的索引意味着这些存储桶仍必须一起排序以满足_id 上的排序。通过将_id放在首位,索引中访问的所有文档都会提前正确排序。

请注意,这比 Andre 的建议({ _id: -1, user_id: 1, cl: 1 },这也应该避免 scanAndOrder)略有改进,因为它允许对 cl 进行直接等效检查以修剪结果。

查看http://blog.mongolab.com/2012/06/cardinal-ins/了解更多详情。

【讨论】:

    【解决方案2】:

    因为您使用的是$lt,所以我不知道您是否能够从查询中删除scanAndOrder 操作。常规公理是您将排序字段作为索引的最后一个成员,但这会在进行范围查询的地方分解。您通常可以通过反转索引的顺序,将排序字段作为第一个成员插入来解决此问题。在您的情况下还有一个问题,因为集合是分片的,因此您可能总是至少选择分片键索引而不是“倒序索引”。

    在不了解数据分布的情况下,很难推荐具体的行动方案。从我所做的简短测试中,将索引添加到{cl:1,user_id:1,_id:-1} 大致将nscannednscannedobjects 减半。这将使用排序字段作为索引的最后一个成员,但存在如上所述的缺陷。你也可以试试这个{_id:1,user_id:1,cl:-1} 的逆操作,但你可能会发现分片键会被该索引选中。您可以进一步尝试通过提示强制反向索引,但这并没有在我的测试中带来任何性能提升。

    【讨论】:

      【解决方案3】:

      尝试 Dex 以确保索引按您认为的方式运行:https://github.com/mongolab/dex

      【讨论】:

        【解决方案4】:

        AFAIK、条件运算符 $gt、$lt 等(mongo 查询中的比较函数)使 mongo 完全不使用索引(对于查询的那部分)。 Mongo 必须扫描集合中的所有文档才能执行此类查询。

        所以,这部分:

        find({ cl:"2012-03", user_id:{$in:users}, _id:{"$lt":new ObjectId('4f788b54204cfa4946000044')} })

        不会使用索引,即使它存在。这让它变慢了。

        更新 查询中的条件运算符 $gt、$lt 等允许使用索引,但不如没有它们那么有效。仍然 mongodb 必须扫描更多返回结果的文档。

        【讨论】:

          猜你喜欢
          • 2021-01-17
          • 1970-01-01
          • 2016-03-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-01-01
          相关资源
          最近更新 更多