【问题标题】:Mongodb index, should partialfilters also be included in the index?Mongodb索引,partialfilters是否也应该包含在索引中?
【发布时间】:2020-03-27 16:50:08
【问题描述】:

我有一个这样的查询:

collection.find({
  type: "person",
  image: {
    $exists: true
  }
}, {
  sort: [
    ["age", -1]
  ],
  limit: 9,
)

如果我已经过滤了字段,是否需要将它们包含在索引中?

collection.createIndex(
  {type: 1, image: 1, age: -1}, 
  { 
    partialFilterExpression: {
      type: 'person',
      image: {
        $exists: true
      }
    },
    background: true
  }
)

或者它是否已经通过部分过滤器表达式知道并且我只查询未修复的内容?

collection.createIndex(
  {age: -1}, 
  { 
    partialFilterExpression: {
      type: 'person',
      image: {
        $exists: true
      }
    },
    background: true,
    name: "ageIndex"
  }
)

想一想,也许正确的做法是不索引所有字段而是使用hint强制db使用索引?

collection.find({
  type: "person",
  image: {
    $exists: true
  }
}, {
  sort: [
    ["age", -1]
  ],
  limit: 9,
).hint("ageIndex")

这真的会正确使用索引并忽略集合中的其他文档吗?

【问题讨论】:

    标签: mongodb mongodb-query mongodb-indexes


    【解决方案1】:

    根据MongoDB Partial Index documentation,如果在此表达式中执行查询,则如果它们已经在 partialFilterExpression 中,则无需将字段包含在索引中。

    以下索引非常适合提供的查询。

    collection.createIndex(
      {age: -1}, 
      {partialFilterExpression: { type: 'person', image: { $exists: true }}}
    )
    

    查询:

    collection.find({type: "person", image: { $exists: true }}, {sort: [["age", -1]])
    

    甚至提示都不是必需的。

    重要提示:如果类型不是“人”,或者不提供图像过滤器,则索引将不起作用。

    如果查询结果 100% 在索引中,则索引将起作用。

    文档中的另一个示例:

    索引:

    db.restaurants.createIndex(
       { cuisine: 1, name: 1 },
       { partialFilterExpression: { rating: { $gt: 5 } } }
    )
    

    查询:

    db.restaurants.find( { cuisine: "Italian", rating: { $lt: 8 } } )
    

    此查询不属于上述索引,因为它包含低于 5 的评分。

    【讨论】:

      【解决方案2】:

      考虑正在查询的示例文档的集合,如问题中所示:

      { _id: 1, type: "person", image: "i-1", age: 19, "fld": 12 },
      { _id: 2, type: "person", image: "i-2", age: 22, "fld": 121 },
      { _id: 3, type: "thing", image: "i-99", age: 29, "fld": 1212 },    // 'type' not 'person'
      { _id: 4, type: "person", age: 31, "fld": 12121 },                 // 'image' missing
      { _id: 5, type: "person", image: "i-3", age: 13, "fld": 121212 },
      { _id: 6, type: "person", age: 43, "fld": 1212121 },               // 'image' missing
      { _id: 7, type: "person", image: "i-4", age: 20, "fld": 1 }
      

      如果我已经拥有这些字段,是否需要将它们包含在索引中 过滤?或者它是否已经通过部分过滤器表达式知道 而我只查询未修复的内容?

      创建一个索引

      db.collection.createIndex( { type: 1, age: -1 },
        {
           partialFilterExpression: {
             type: 'person',
             image: { $exists: true }
          }
        }
      )
      

      请注意,索引字段仅在 typeage 上。为什么?这在下面的索引使用验证中进行了解释。

      查询

      db.collection.find( { type: "person", image: { $exists: true } } ).sort( { age: -1 } )
      

      结果

      查询以排序顺序返回预期的过滤文档

      { "_id" : 2, "type" : "person", "image" : "i-2", "age" : 22, "fld" : 121 }
      { "_id" : 7, "type" : "person", "image" : "i-4", "age" : 20, "fld" : 1 }
      { "_id" : 1, "type" : "person", "image" : "i-1", "age" : 19, "fld" : 12 }
      { "_id" : 5, "type" : "person", "image" : "i-3", "age" : 13, "fld" : 121212 }
      


      索引使用验证:

      可以通过使用explain方法生成查询计划来验证索引的使用情况:

      db.collection.find( { type: "person", image: { $exists: true } } ).sort( { age: -1 } ).explain()
      

      计划输出显示过滤器排序操作的索引使用情况。这在计划中被标记为 IXSCAN(索引扫描)和 SORT 阶段的缺席。这是该查询的索引的正确用法。

      在索引定义中,type + age 这两个字段指定了一个复合索引。这是要求将索引应用于type(用于过滤)和age(用于排序)。字段image 不能在索引定义中指定,因为它不与相等条件一起使用 条件(使用$exists);如果指定,索引将不会用于以下排序字段(来自documentation):

      索引可以支持对非前缀子集的排序操作 索引键模式。为此,查询必须包含相等 排序键之前的所有前缀键的条件。

      查询计划(其中的一部分):

      {
          "queryPlanner" : {
                  "plannerVersion" : 1,
                  "namespace" : "test.persons",
                  "indexFilterSet" : false,
                  "parsedQuery" : {
                          "$and" : [
                                  {
                                          "type" : {
                                                  "$eq" : "person"
                                          }
                                  },
                                  {
                                          "image" : {
                                                  "$exists" : true
                                          }
                                  }
                          ]
                  },
                  "queryHash" : "25E877F5",
                  "planCacheKey" : "C9D745BE",
                  "winningPlan" : {
                          "stage" : "FETCH",
                          "filter" : {
                                  "image" : {
                                          "$exists" : true
                                  }
                          },
                          "inputStage" : {
                                  "stage" : "IXSCAN",
                                  "keyPattern" : {
                                          "type" : 1,
                                          "age" : -1
                                  },
                                  "indexName" : "type_1_age_-1",
                                  "isMultiKey" : false,
                                  "multiKeyPaths" : {
                                          "type" : [ ],
                                          "age" : [ ]
                                  },
                                  "isUnique" : false,
                                  "isSparse" : false,
                                  "isPartial" : true,
                                  "indexVersion" : 2,
                                  "direction" : "forward",
                                  "indexBounds" : {
                                          "type" : [
                                                  "[\"person\", \"person\"]"
                                          ],
                                          "age" : [
                                                  "[MaxKey, MinKey]"
                                          ]
                                  }
                          }
                  }, ...
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-02-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-03
        • 1970-01-01
        • 2021-04-29
        • 1970-01-01
        相关资源
        最近更新 更多