2017-07-03 69 views
3

我已經創建了我的收集提供了以下指標:MongoDB的查詢不會對複合索引使用前綴文本字段

db.myCollection.createIndex({ 
    user_id: 1, 
    name: 'text' 
}) 

如果我嘗試看看包含這兩個字段的查詢的執行計劃,這樣:

db.getCollection('campaigns').find({ 
    user_id: ObjectId('xxx') 
    ,$text: { $search: 'bla' } 
}).explain('executionStats') 

我得到如下結果:

... 
"winningPlan" : { 
    "stage" : "TEXT", 
    "indexPrefix" : { 
     "user_id" : ObjectId("xxx") 
    }, 
    "indexName" : "user_id_1_name_text", 
    "parsedTextQuery" : { 
     "terms" : [ 
      "e" 
     ], 
     "negatedTerms" : [], 
     "phrases" : [], 
     "negatedPhrases" : [] 
    }, 
    "inputStage" : { 
     "stage" : "TEXT_MATCH", 
     "inputStage" : { 
      "stage" : "TEXT_OR", 
      "inputStage" : { 
       "stage" : "IXSCAN", 
       "keyPattern" : { 
        "user_id" : 1.0, 
        "_fts" : "text", 
        "_ftsx" : 1 
       }, 
       "indexName" : "user_id_1_name_text", 
       "isMultiKey" : true, 
       "isUnique" : false, 
       "isSparse" : false, 
       "isPartial" : false, 
       "indexVersion" : 1, 
       "direction" : "backward", 
       "indexBounds" : {} 
      } 
     } 
    } 
} 
... 

正如documentation指出, MongoDB可以使用索引前綴來執行索引查詢。

由於user_id是該指數的前綴之上,我預計,只有user_id查詢將使用索引,但如果我嘗試以下方法:

db.myCollection.find({ 
    user_id: ObjectId('xxx') 
}).explain('executionStats') 

我得到:

... 
"winningPlan" : { 
    "stage" : "COLLSCAN", 
    "filter" : { 
     "user_id" : { 
      "$eq" : ObjectId("xxx") 
     } 
    }, 
    "direction" : "forward" 
}, 
... 

因此,它根本沒有使用索引並執行完整的集合掃描。

回答

3

一般來說,MongoDB可以使用索引前綴來支持查詢,但是複合索引(包括地理空間或文本字段)是sparse compound indexes的特例。如果文檔不包含複合索引中任何文本索引字段的值,則它不會包含在索引中。

爲了確保correct results爲前綴搜索,另一種查詢計劃將選擇在稀疏複合索引:

如果稀疏索引會導致結果不完整的組查詢和排序操作,除非一個hint()明確指定索引,否則MongoDB不會使用該索引。

設置MongoDB中3.4.5一些測試數據,以證實潛在的問題:

db.myCollection.createIndex({ user_id:1, name: 'text' }, { name: 'myIndex'}) 

// `name` is a string; this document will be included in a text index 
db.myCollection.insert({ user_id:123, name:'Banana' }) 

// `name` is a number; this document will NOT be included in a text index 
db.myCollection.insert({ user_id:123, name: 456 }) 

// `name` is missing; this document will NOT be included in a text index 
db.myCollection.insert({ user_id:123 }) 

然後,迫使化合物文本索引中使用:僅

db.myCollection.find({user_id:123}).hint('myIndex') 

結果包括索引文本字段name的單個文檔,而不是預期的三個文檔:

{ 
    "_id": ObjectId("595ab19e799060aee88cb035"), 
    "user_id": 123, 
    "name": "Banana" 
} 

這個異常應該在MongoDB文檔中更清楚地突出顯示;在MongoDB問題跟蹤器中觀看/上傳DOCS-10322以獲取更新。

+0

所以,基本上這裏的解決方案,因爲我需要兩個查詢,將有2個索引:1個單獨包含'user_id',另一個包含'{user_id,name}'? –

+0

@HenriqueBarcelos是的,你需要'user_id'上的單獨索引。這可能是另一個非稀疏複合索引的前綴。 – Stennie

1

這種現象是由於文本索引被sparse by default

對於包括與其他 類型的鍵沿文本索引鍵的化合物指數,僅文本索引字段確定是否索引 引用一個文件。其他鍵不確定 索引是否引用文檔。

查詢過濾器不引用文本索引字段,那麼查詢規劃不會考慮這個指標,因爲它不能確定,充分結果集的文件將通過索引返回。

相關問題