为什么MongoDB在从同一索引提供时以不同方式处理查询?

时间:2017-05-24 11:00:35

标签: mongodb

我的文档看起来像是一个集合:

{
  "_id" : ObjectId("591dbe4a77d4ede22d765250"),
  "name" : [
    {
      "de" : true,
      "text" : "Brunhilde"
    },
    {
      "sk" : true,
      "text" : "Šimon"
    }
  ]
}

我已将索引定义为:

> db.names.createIndex({ 'name.de': 1, 'name.text': 1 }, {  name: 'name_de', partialFilterExpression: { 'name.de': { $exists: true } }, collation: { locale: 'de' } });

当我进行如下查询时:

> db.names.find({ 'name.de': true, 'name.text': 'Rüdi' }).collation({ locale: 'de' });    

解释计划如下:

"winningPlan" : {
  "stage" : "FETCH",
  "filter" : {
    "name.text" : {
      "$eq" : "Rüdi"
    }
  },
  "inputStage" : {
    "stage" : "IXSCAN",
    "keyPattern" : {
      "name.de" : 1,
      "name.text" : 1
    },
    "indexName" : "name_de",
    "collation" : {
      "locale" : "de",
      "caseLevel" : false,
      "caseFirst" : "off",
      "strength" : 3,
      "numericOrdering" : false,
      "alternate" : "non-ignorable",
      "maxVariable" : "punct",
      "normalization" : false,
      "backwards" : false,
      "version" : "57.1"
    },
    "isMultiKey" : true,
    "multiKeyPaths" : {
      "name.de" : [
        "name"
      ],
      "name.text" : [
        "name"
      ]
    },
    "isUnique" : false,
    "isSparse" : false,
    "isPartial" : true,
    "indexVersion" : 2,
    "direction" : "forward",
    "indexBounds" : {
      "name.de" : [
        "[true, true]"
      ],
      "name.text" : [
        "[MinKey, MaxKey]"
      ]
    }
  }
}

它使用IXSCAN,然后是带过滤器的FETCH阶段。我已经创建了有关过滤器here的问题。 更有趣的是当我将查询的匹配部分更改为:

时会发生什么
> db.names.find({ 'name.de': { $exists: true }, 'name.text': 'Rüdi' }).collation({ locale: 'de' });

即。表达式'name.de': { $exists: true }应该仍然是partialFilterExpression的子集。如文档中所述:

  

要使用部分索引,查询必须包含过滤器表达式(或指定过滤器表达式子集的已修改过滤器表达式)作为其查询条件的一部分。

但解释计划如下:

...
"winningPlan" : {
  "stage" : "FETCH",
  "filter" : {
    "$and" : [
      {
        "name.de" : {
          "$exists" : true
        }
      },
      {
        "name.text" : {
          "$eq" : "Rüdi"
        }
      }
    ]
  },
  "inputStage" : {
    "stage" : "IXSCAN",
    "keyPattern" : {
      "name.de" : 1,
      "name.text" : 1
    },
    "indexName" : "name_de",
    "collation" : {
      "locale" : "de",
      "caseLevel" : false,
      "caseFirst" : "off",
      "strength" : 3,
      "numericOrdering" : false,
      "alternate" : "non-ignorable",
      "maxVariable" : "punct",
      "normalization" : false,
      "backwards" : false,
      "version" : "57.1"
    },
    "isMultiKey" : true,
    "multiKeyPaths" : {
      "name.de" : [
        "name"
      ],
      "name.text" : [
        "name"
      ]
    },
    "isUnique" : false,
    "isSparse" : false,
    "isPartial" : true,
    "indexVersion" : 2,
    "direction" : "forward",
    "indexBounds" : {
      "name.de" : [
        "[MinKey, MaxKey]"
      ],
      "name.text" : [
        "[MinKey, MaxKey]"
      ]
    }
  }
}  
...

正如您所见,使用了索引,但整个过滤都发生在FETCH阶段。

问题是:为什么过滤在FETCH阶段完成,而这两个查询之间有什么不同,MongoDB它们的区别是什么?

另外,将查询与$exists排序为:

> db.names.find({ 'name.de': { $exists: true } }).sort({ 'name.text': 1 }).collation({ locale: "de" })

行为相同,在IXSCAN阶段之后完成整个过滤和排序:

...
"winningPlan" : {
      "stage" : "SORT",
      "sortPattern" : {
        "name.text" : 1
      },
      "inputStage" : {
        "stage" : "SORT_KEY_GENERATOR",
        "inputStage" : {
          "stage" : "FETCH",
          "filter" : {
            "name.de" : {
              "$exists" : true
            }
          },
          "inputStage" : {
            "stage" : "IXSCAN",
            "keyPattern" : {
              "name.de" : 1,
              "name.text" : 1
            }
...

它甚至会产生不正确的结果,而索引不用于排序。

0 个答案:

没有答案