使用存在運算符時,MongoDB 覆蓋查詢需要獲取和檢查文件
我需要在 mongo db 上執行以下查詢:
db.testCollection.find({ dataType: { $exists: true } }, { _id: 0, date: 1 }) .sort({ date: -1 }) .limit(1)
所以基本上我需要做的就是從有
dataType
欄位的文件中找到最新的日期。我在該集合中有大約 2000 萬份文件,此查詢持續大約 4-5 分鐘。我試圖通過索引覆蓋所有查詢需求,所以我創建了這樣的索引:db.testCollection.ensureIndex( { dataType: 1, date: -1 }, { partialFilterExpression: { dataType: { $exists: true } } } )
據我所知,該索引包含查詢所需的所有數據:
- 該索引中的所有文件都包含
dataType
欄位的資訊存在date
從查詢中檢索它所需的欄位值date
排序操作所需的欄位值
FETCH
不幸的是,mongo在查詢計劃中仍然有階段來檢查文件是否dataType
存在:"winningPlan" : { "stage" : "PROJECTION_SIMPLE", "transformBy" : { "_id" : 0, "date" : 1 }, "inputStage" : { "stage" : "SORT", "sortPattern" : { "date" : -1 }, "limitAmount" : 1, "inputStage" : { "stage" : "SORT_KEY_GENERATOR", "inputStage" : { "stage" : "FETCH", "filter" : { "dataType" : { "$exists" : true } }, "inputStage" : { "stage" : "IXSCAN", "keyPattern" : { "dataType" : 1, "date" : -1 }, "indexName" : "dataType_1_date_-1", "isMultiKey" : false, "multiKeyPaths" : { "dataType" : [ ], "date" : [ ] }, "isUnique" : false, "isSparse" : false, "isPartial" : true, "indexVersion" : 2, "direction" : "forward", "indexBounds" : { "dataType" : [ "[MinKey, MaxKey]" ], "date" : [ "[MaxKey, MinKey]" ] } } } } } }
所以我的問題是為什麼 mongo 仍然需要從集合中獲取文件?
編輯:當我將
$exists
操作員更改為$ne: null
它不需要執行FETCH
階段。
在 MongoDB v4.2.8 上嘗試使用發布的資訊時,我看到了類似的結果。
通常,
$exists
查詢中的過濾器使用該欄位上的索引。例如,如果有一個欄位fld1
並且您使用過濾器執行查詢{ fld1: {$exists: true}}
,則查詢使用索引。在查詢計劃輸出中,記憶體排序(“stage”:“SORT”)是因為 - 對於復合索引,過濾器必須是索引前綴欄位()上的相等條件
dataType
,然後只有索引將用於使用該date
欄位的排序操作。FETCH 用於在記憶體中進行 SORT 操作(即,未使用索引)。因此,查詢不包括在內。例如,像這樣的查詢將使用索引(並且將被覆蓋):
db.test.find({ dataType: "a" }, { date: 1, _id: 0 }).sort({ date: -1 })
重要的是要注意查詢過濾器
{ dataType: "a" }
使用相等條件 - 並且{dataType: {$exists: true}}
沒有。請參閱索引的排序和非前綴子集
索引規範
{ dataType: 1, date: -1 }
意味著索引條目將首先按 排序dataType
,然後按 排序date
。這與查詢請求的排序不匹配:
{ date: -1 }
.如果您要像下面這樣建構索引,則查詢執行可以避免使用記憶體排序,並且只檢查 1 個文件,這應該會提供更好的性能。
db.testCollection.ensureIndex( { date: -1 }, { partialFilterExpression: { dataType: { $exists: true } } } )