Index

使用存在運算符時,MongoDB 覆蓋查詢需要獲取和檢查文件

  • March 23, 2022

我需要在 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 } } }
)

引用自:https://dba.stackexchange.com/questions/280377