我正在编写一个需要在两个表之间进行$查询的查询,据我所知,为了及时执行此连接,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。有什么想法我可能做错了吗?提前谢谢!
答案 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"
。