2015-06-03 27 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