2つのテーブル間で$ 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" : [ ]
}
前述したように、トランザクションコレクションでidフィールドにインデックスが付けられています。
> 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万のドキュメントのDBで実行されるのに数分かかります。 MongoDBv3.4.7を使用しています。私が間違っている可能性があることについて何か考えはありますか?前もって感謝します!
"stage" : "COLLSCAN",
は$lookup
をまったく参照していません。
その集約パイプラインの最初のステップは、「users」コレクションからすべてのドキュメントをフェッチすることです。そのためのフィルターはまったく提供されていないため、コレクションスキャンが最も効率的な方法です。
$ lookupステージは、他のクエリと同じように計画する必要があり、インデックスを使用する可能性があります。
集約パイプラインの最初のステージには、インデックス付きキーに対する$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
を適切に使用できないため、あまり多くのインデックスを作成しないでください。