MongoDB $查找不使用索引

时间:2017-08-29 12:33:23

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

我正在编写一个需要在两个表之间进行$查询的查询,据我所知,为了及时执行此连接,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" : [ ]
}

正如我所提到的,我确实在事务集合中索引了 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。有什么想法我可能做错了吗?提前谢谢!

2 个答案:

答案 0 :(得分:4)

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

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

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

答案 1 :(得分:0)

因为您的聚合管道的第一阶段没有With Sheets("Tabelle2") .Range(.Cells(1, "A), .Cells(Wert, "B")).Copy End With $match 或在索引键上$sort进行查询,在$ match阶段,您没有在任何索引键上进行查询。

情况1:如果在第一阶段对索引键进行$ match,则$geoNear阶段将为WinningPlan"FETCH"阶段将为{{ 1}}

inputStage

情况2:如果在第一阶段对未索引的密钥进行$ match,则"IXSCAN"阶段将为"winningPlan" : { "stage" : "FETCH", "inputStage" : { "stage" : "IXSCAN", ... } }

WinningPlan

情况3::如果您在查询后对索引键进行了$ match(根据查询),则"COLLSCAN"阶段将为"winningPlan" : { "stage" : "COLLSCAN" } WinningPlan阶段是"FETCH"

情况4::如果您在查找后对非索引键执行了$ match(就像您所做的那样),则inputStage阶段将为"IXSCAN"

对于7M记录,必须在查询中使用索引。不要做太多索引,因为它们将存储在RAM中,并且您不能在索引键上正确使用WinningPlan"COLLSCAN"

Mongodb Docs: Optimizing Aggregation Pipeline

Mongodb Docs: Indexing Strategies