2017-04-10 60 views
0

我有一個問題,爲我的mongo查詢生成適當的索引,這將避免SORT階段。我甚至不確定在我的情況下是否可能。因此,這裏是我的查詢與執行統計​​:這就是爲什麼「M」不包含在任何索引

db.getCollection('test').find(
{ 
    "$or" : [ 
    { 
     "a" : { "$elemMatch" : { "_id" : { "$in" : [4577] } } }, 
     "b" : { "$in" : [290] }, 
     "c" : { "$in" : [35, 49, 57, 101, 161, 440] }, 
     "d" : { "$lte" : 399 } 
    }, 
    { 
     "e" : { "$elemMatch" : { "numbers" : { "$in" : ["1K0407151AC", "0K20N51150A"] } } }, 
     "d" : { "$lte" : 399 } 
    }] 
}) 
.sort({ "X" : 1, "d" : 1, "Y" : 1, "Z" : 1 }).explain("executionStats") 

字段「M」,「a」和「E」是數組,

如果您檢查execution stats屏幕截圖,您會看到內存使用情況非常接近最大值,不幸的是,由於32MB的限制,我查詢的查詢未能執行。

指數爲$或查詢的第一部分: { 「a._id」:1, 「X」:1, 「d」:1, 「Y」:1, 「Z 「:1, 」b「:1, 」C「:1 }

指數爲$或查詢的第二部分: { 」e.numbers「:1, 」X「: 1, 「d」:1, 「Y」:1, 「Z」:1 }

索引由查詢使用,但不用於排序。而不是SORT階段,我希望看到SORT_MERGE階段,但現在沒有成功。如果我在$或者單獨運行部分查詢,他們可以使用索引來避免在內存中排序。作爲一種解決方法,它是可以的,但我需要合併並通過應用程序對結果進行求值。

MongoDB版本是3.4.2。我檢查了thatthat的問題。我的查詢是結果。可能我錯過了什麼?

編輯:蒙戈文件看起來像:

{ 
    "_id" : "290_440_K760A03", 
    "Z" : "K760A03", 
    "c" : 440, 
    "Y" : "NPS", 
    "b" : 290, 
    "X" : "Schlussleuchte", 
    "e" : [ 
     { 
      "..." : 184, 
      "numbers" : [ 
       "0K20N51150A" 
      ] 
     } 
    ], 
    "a" : [ 
     { 
      "_id" : 4577, 
      "..." : [ 
       { 
        "..." : [ 
         { 
          "..." : "R", 
         } 
        ] 
       } 
      ] 
     }, 
     { 
      "_id" : 4578    
     } 
    ], 
    "d" : 101, 
    "m" : [ 
     "AT", 
     "BR", 
     "CH" 
    ], 
    "moreFields":"..." 
} 

編輯2:刪除申請「M」從查詢到減少的人,誰願意幫助的複雜性和attached測試收集轉儲: )

+0

根據您鏈接到的第一個問題的答案,兩個指數都需要在' 「X」 來_END_:1, 「d」:1, 「Y」:1, 「Z」:1'一個SORT_MERGE ,不只是包含這些領域。 – JohnnyHK

+0

@JohnnyHK,將第一個索引改爲「{」a._id「:1,」X「:1,」d「:1,」Y「:1,」Z「:1}但沒有成功。排序仍然在內存中,查詢變得更慢。 – stoos

+0

可以請您添加一個或兩個數據的實例 –

回答

0

這裏是解決方案- 我剛剛在我的測試集合中添加了一個文檔,如您的問題(編輯部分)所示。然後我四個以下indices-

1. {"m":1,"b":1,"c":1,"X":1,"d":1,"Y":1,"Z":1} 
2. {"a._id":1,"b":1,"c":1,"X":1,"d":1,"Y":1,"Z":1} 
3. {"m":1,"X":1,"d":1,"Y":1,"Z":1} 
4. {"e.numbers":1,"X":1,"d":1,"Y":1,"Z":1} 

創建,並在我執行給定的查詢執行的統計數據,然後它讓我看到SORT_MERGE狀態的預期。

這裏是解釋- MongoDB有一個叫equality-sort-range的東西,它告訴我們應該如何創建我們的索引。我只是遵循這個規則,並按照這個順序保留了索引。所以這裏的指數應該是{Equality fields, "X":1,"d":1,"Y":1,"Z":1, Range fields}。您可以看到查詢僅在字段「d」上有範圍("d" : { "$lte" : 101 }),但索引的SORT字段("X":1,"d":1,"Y":1,"Z":1)已包含「d」,因此我們可以從索引結尾跳過範圍部分(即字段「d」) 。

如果「d」沒有在排序/相等謂詞中,那麼我會將它作爲範圍索引字段的索引,我的索引看起來像{Equality fields, "X":1,"Y":1,"Z":1,"d":1}

現在我的索引是{Equality fields, "X":1,"d":1,"Y":1,"Z":1},我只關心平等領域。因此,爲了找出相等字段,我只查詢了查詢謂詞,並發現有兩個條件由OR運算符組合。

  • 第一個條件具有相等的"a._id", "b", "c", "m"(「d」有範圍,不等於)。所以我需要創建一個像"a._id":1,"m":1,"b":1,"c":1,"X":1,"d":1,"Y":1,"Z":1這樣的索引,但是這會給出錯誤,因爲它有兩個數組字段「a_id」和「m」。而且據我們所知,Mongo不允許compound index on parallel arrays,所以它會失敗。所以我創建了兩個單獨的索引,以允許Mongo使用查詢規劃器所選擇的內容。因此我創建了第一個和第二個索引。
  • OR運算符的第二個條件是「e.numbers」和「m」。兩者都是數組字段,所以我必須爲第一個條件創建兩個索引,這就是我獲得第三個和第四個索引的方式。

現在我們知道,一次只能使用一個查詢,只有一個索引,所以我需要創建這些索引,因爲我不知道OR運算符的哪個分支將被執行。

注意:如果您擔心索引的大小,那麼您只能保留前兩個索引和後兩個索引。或者你也可以保留所有四個,並提示mongo使用適當的索引,如果你知道它之前查詢計劃。

+0

我編輯了我的問題並添加了一個測試集合。索引1和3現在可以刪除。不幸的是,即使我改變了索引2,因爲我的答案仍然存在SORT階段。使用這個索引2,您將在$或查詢的第一部分('「a」:{「$ elemMatch」:{「_id」:{「$ in」:[4577]}}}, 中擁有SORT_MERGE階段「 b「:{」$ in「:[290]}, 」c「:{」$ in「:[35,49,57,101,161,440]}, 」d「:{」$ lte「 :399}')如果你使用這個索引,你完全可以避免:{「a._id」:1,「X」:1,「d」:1,「Y」:1,「Z」:1, b「:1,」c「:1}。 – stoos

+0

評論的大小是不夠的,所以我會發布第二個:)你說關於平等排序範圍的正確的事情,但也許你誤解了一點。請閱讀這篇文章:https://blog.mlab.com/2012/06/cardinal-ins/無論如何,我想再次感謝你的時間。 – stoos

+0

感謝stoos給予那個鏈接並糾正我。您的問題是否仍然存在?或者它是否按預期工作? –