MongoDB$查找未使用索引

MongoDB$查找未使用索引,mongodb,mongodb-query,aggregation-framework,mongodb-shell,Mongodb,Mongodb Query,Aggregation Framework,Mongodb Shell,我正在编写一个需要在两个表之间进行$lookup的查询,据我所知,foreignField必须有一个索引,以便及时执行此联接。但是,即使在字段上添加了索引,查询仍会退回到COLLSCAN db.users.aggregate([ {$lookup:{ from: "transactions", localField: '_id', foreignField: 'uid', as: 'transaction' }}, { $match: { transaction: { "$size" :

我正在编写一个需要在两个表之间进行$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"
    }
]
在一个包含大约700万个文档的数据库中运行查询需要几分钟的时间。我正在使用MongoDB v3.4.7。知道我做错了什么吗?提前谢谢

“阶段”:“COLLSCAN”根本不是指
$lookup

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


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

因为聚合管道第一阶段没有
$match
$sort
或者,
$geoNear
查询索引键,而在$match阶段,您没有查询任何索引键

案例1:如果您在第一阶段对索引键进行$match,
Winning Plan
阶段将是
“FETCH”
inputStage
阶段将是
“IXSCAN”

案例2:如果您在第一阶段对非索引键进行$match,
Winning Plan
阶段将是
“COLLSCAN”

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

案例4:如果您在查找后对非索引键执行$match(就像您执行的那样),
WinningPlan
阶段将是
“COLLSCAN”

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


在聚合管道中唯一可以使用索引的阶段是第一阶段,该阶段必须是
$match
$geoNear
$sort
。虽然
$lookup
可能会在“外键”上使用索引,但目前统计数据中并未报告这一点。对于您在这里尝试的内容,不可能使用索引。请注意:在MongoDB上使用关系数据模型并试图使其更SQLish,这要么是数据建模不好的迹象,要么是技术决策不好。每次我在描述为查询的聚合中看到
$lookup
,都可以通过正确的数据建模来摆脱它。感谢您提供的信息!我不知道在查找阶段需要使用索引。@NeilLunn 3.6版的规则已经更改,似乎任何阶段现在都可以使用索引。您可以添加这两个集合的示例文档吗?
"winningPlan" : {
    "stage" : "FETCH",
    "inputStage" : {
            "stage" : "IXSCAN",
        ...
    }
}
"winningPlan" : {
    "stage" : "COLLSCAN"
}