【发布时间】: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