2015-06-03 63 views
8

我試圖重現指數路口指令(http://docs.mongodb.org/manual/core/index-intersection/)的第一個例子,但面臨的一個問題:蒙戈不使用股指雙雙爲什麼MongoDB不使用索引相交?

我的步驟:

  1. 下載蒙戈(3.0.3)和安裝
  2. 運行的mongod:mongod.exe --dbpath d:\數據(文件夾爲空)
  3. 運行蒙戈:mongo.exe
  4. 添加索引:

    db.orders.ensureIndex({ qty: 1 }) 
    db.orders.ensureIndex({ item: 1 }) 
    db.orders.getIndexes() 
    [{ 
         "v" : 1, 
         "key" : { 
           "_id" : 1 
         }, 
         "name" : "_id_", 
         "ns" : "test.orders" 
    }, 
    { 
         "v" : 1, 
         "key" : { 
           "qty" : 1 
         }, 
         "name" : "qty_1", 
         "ns" : "test.orders" 
    }, 
    { 
         "v" : 1, 
         "key" : { 
           "item" : 1 
         }, 
         "name" : "item_1", 
         "ns" : "test.orders" 
    }] 
    
  5. 檢查查詢說明:

    db.orders.find({ item: "abc123", qty: { $gt: 15 } }).explain() 
    { 
        "queryPlanner" : { 
          "plannerVersion" : 1, 
          "namespace" : "test.orders", 
          "indexFilterSet" : false, 
          "parsedQuery" : { 
            "$and" : [ 
              { 
                "item" : { 
                  "$eq" : "abc123" 
                } 
              }, 
              { 
                "qty" : { 
                  "$gt" : 15 
                } 
              } 
            ] 
          }, 
          "winningPlan" : { 
            "stage" : "KEEP_MUTATIONS", 
            "inputStage" : { 
              "stage" : "FETCH", 
              "filter" : { 
                "qty" : { 
                  "$gt" : 15 
                } 
              }, 
              "inputStage" : { 
                "stage" : "IXSCAN", 
                "keyPattern" : { 
                  "item" : 1 
                }, 
                "indexName" : "item_1", 
                "isMultiKey" : false, 
                "direction" : "forward", 
                "indexBounds" : { 
                  "item" : [ 
                    "[\"abc123\", \"abc123\"]" 
                  ] 
                } 
              } 
            } 
          }, 
          "rejectedPlans" : [ 
            { 
              "stage" : "KEEP_MUTATIONS", 
              "inputStage" : { 
                "stage" : "FETCH", 
                "filter" : { 
                  "item" : { 
                    "$eq" : "abc123" 
                  } 
                }, 
                "inputStage" : { 
                  "stage" : "IXSCAN", 
                  "keyPattern" : { 
                    "qty" : 1 
                  }, 
                  "indexName" : "qty_1", 
                  "isMultiKey" : false, 
                  "direction" : "forward", 
                  "indexBounds" : { 
                    "qty" : [ 
                      "(15.0, 1.#INF]" 
                    ] 
                  } 
                } 
              } 
            } 
          ] 
        }, 
        "serverInfo" : { 
          "host" : "localhost", 
          "port" : 27017, 
          "version" : "3.0.3", 
          "gitVersion" : "b40106b36eecd1b4407eb1ad1af6bc60593c6105" 
        }, 
        "ok" : 1 
    } 
    

正如你可以看到winningPlan只包含ITEM_1指數。有包含qty_1索引的rejectPlans。但是沒有包含索引交集的計劃。 我知道有很多條件可以選擇特定的索引。但在我的情況下,mongo甚至沒有計劃!

有人能幫助我嗎?

+0

FWIW,與MongoDB 3.0.2相同 –

+0

數據庫中有多少個文檔?什麼「解釋(真)」說?查詢需要多長時間?數據字段的分佈是什麼,如果有的話? – mnemosyn

回答

3

有大約在SERVER-3071 JIRA issue指數選擇的一些細節,但我不能說,如果一切仍然是相關的3.0。無論如何:

MongoDB 3.0.2 似乎不考慮索引交互範圍查詢。但它會爲點間隔:

> db.orders.find({ item: {$eq : "abc123"}, qty: { $eq: 15 } }).explain() 
... 

     { 
      "stage" : "FETCH", 
      "inputStage" : { 
       "stage" : "KEEP_MUTATIONS", 
       "inputStage" : { 
        "stage" : "AND_SORTED", 
        "inputStages" : [ 
         { 
          "stage" : "IXSCAN", 
          "keyPattern" : { 
           "qty" : 1 
          }, 
          "indexName" : "qty_1", 
          "isMultiKey" : false, 
          "direction" : "forward", 
          "indexBounds" : { 
           "qty" : [ 
            "[15.0, 15.0]" 
           ] 
          } 
         }, 
         { 
          "stage" : "IXSCAN", 
          "keyPattern" : { 
           "item" : 1 
          }, 
          "indexName" : "item_1", 
          "isMultiKey" : false, 
          "direction" : "forward", 
          "indexBounds" : { 
           "item" : [ 
            "[\"abc123\", \"abc123\"]" 
           ] 
          } 
         } 
        ] 
       } 
+1

所以基本上索引交叉似乎從來沒有發生在現實生活中的查詢?根據我的測試,對於具有多於1個項目的查詢,$不起作用:( –

+0

觀察與v3.4相同的行爲。10 – mils

+0

進一步觀察:'hint()'不適用於複合索引的前綴(僅適用於整個複合索引);索引交叉點似乎不適用於複合索引前綴(僅適用於單個索引) – mils

1

我們承載一個多租戶網站。因此,有一個蒙戈集合持有所有客戶的一些信息,例如,

{customerId: 22, category: "category", region: "region", balance: 23434... } 

後,我們瞭解到索引交集,我們試圖建立多單字段索引,以支持不同的查詢條件,具有可變領域,如查詢作爲

{ customerId: 22, category: "1" } 
{ customerId: 22, region: "somewhere" } 
{ customerId: 22, balance: {$gt:0} } 
{ customerId: 22, region: {$in: ["R1", "R2"]},balance: {$gt:0} } 
.... 

但它簡單地通過學習「db.collection.explain」沒有發生交集。 由於字段有限,我們終於找到了一個解決方案來構建包含所有字段的複合索引。

{customerId: 1, category: 1, region: 1, balance:1...} 

然後事實證明,下面的所有查詢使用「大」複合索引,只要「客戶ID」是在查詢中。

{ customerId: 22, category: "1" } 
{ customerId: 22, region: "somewhere" } 
{ customerId: 22, balance: {$gt:0} } 
{ customerId: 22, region: {$in: ["R1", "R2"]},balance: {$gt:0} } 
.... 
+0

儘管添加如此大的複合索引並沒有多大幫助。在您提供的四個查詢示例中,最後三個只使用複合索引的'customerId'前綴,而第一個使用複合索引的'customerId'加'類別'前綴。如果您試圖爲這四個查詢建立索引,那麼只有前兩個字段的複合索引會更好。只是說'所以沒有人會得到這樣的想法,一個巨大的複合索引將加速任何查詢過濾任何包含在其中的字段:) – DanielSmedegaardBuus