【问题标题】:MongoDB $lookup not using indexMongoDB $lookup 不使用索引
【发布时间】:2018-02-06 22:06:52
【问题描述】:

我正在编写一个需要在两个表之间进行 $lookup 的查询,据我了解,foreignField 必须有一个索引才能及时执行此连接。但是,即使在字段上添加索引后,查询仍会退回到 COLLSCAN。

db.users.aggregate([
  {$lookup:{ from: "transactions", localField: '_id', foreignField: 'uid', as: 'transaction' }},
  { $match: { transaction: { "$size" : 0} } },
  { $count: "total"},
], { explain: true })

这会返回:

"queryPlanner" : {
    "plannerVersion" : 1,
    "namespace" : "test.users",
    "indexFilterSet" : false,
    "parsedQuery" : {

    },
    "winningPlan" : {
        "stage" : "COLLSCAN",
        "direction" : "forward"
    },
    "rejectedPlans" : [ ]
}

正如我所提到的,我确实在 transactions 集合中索引了 uid 字段:

> db.transactions.getIndexes()
[
    {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "test.transactions"
    },
    {
        "v" : 1,
        "key" : {
            "uid" : 1
        },
        "name" : "uid_1",
        "ns" : "test.transactions"
    }
]

查询需要几分钟才能在大约 7M 文档的数据库中运行。我正在使用 MongoDB v3.4.7。关于我可能做错了什么的任何想法?提前致谢!

【问题讨论】:

  • 唯一可以在聚合管道中使用索引的阶段是第一个,并且必须是$match$geoNear$sort。虽然$lookup 可能会在“外键”上使用索引,但目前尚未在统计数据中报告。对于您在此处尝试的内容,无法使用索引。
  • 附带说明:在 MongoDB 上使用关系数据模型并尝试使其更加 SQLish 是数据建模不佳或技术决策不佳的标志。每次我在描述为查询的聚合中看到$lookup 时,都可以通过适当的数据建模来摆脱它。
  • 感谢您的信息!我不知道在查找阶段需要使用索引。
  • @NeilLunn 3.6 的规则已经改变,现在似乎任何阶段都可以使用索引docs.mongodb.com/manual/core/aggregation-pipeline/…
  • 你能添加两个集合的示例文档吗?

标签: mongodb mongodb-query aggregation-framework mongodb-shell


【解决方案1】:

"stage" : "COLLSCAN", 根本不是指$lookup

聚合管道的第一步是从“用户”集合中获取所有文档。由于根本没有为此提供过滤器,因此集合扫描是最有效的方法。

$lookup 阶段应该像任何其他查询一样进行规划,并且可能会使用索引。

【讨论】:

    【解决方案2】:

    因为您的聚合管道第一阶段没有$match$sort$geoNear 查询索引键和在 $match 阶段您没有查询任何索引键。

    案例1:如果你在第一阶段对索引键进行$match,WinningPlan阶段将是"FETCH"inputStage阶段将是"IXSCAN"

    "winningPlan" : {
        "stage" : "FETCH",
        "inputStage" : {
                "stage" : "IXSCAN",
            ...
        }
    }
    

    案例2:如果你在第一阶段对非索引键进行$match,WinningPlan阶段将是"COLLSCAN"

    "winningPlan" : {
        "stage" : "COLLSCAN"
    }
    

    案例 3:如果您在查找后对索引键执行 $match(根据您的查询),WinningPlan 阶段将是 "FETCH"inputStage 将是 "IXSCAN"

    案例 4:如果您在查找后对非索引键执行 $match(只是您这样做了),WinningPlan 阶段将是 "COLLSCAN"

    对于 7M 的记录,您必须在查询中使用索引。不要做太多索引,因为它们会存储在 RAM 中,你不能在索引键上正确使用 $ne$nin

    Mongodb Docs: Optimizing Aggregation Pipeline

    Mongodb Docs: Indexing Strategies

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多