【问题标题】:Why Mongo query for null filters in FETCH after performing IXSCAN为什么在执行 IXSCAN 后 Mongo 在 FETCH 中查询空过滤器
【发布时间】:2017-08-23 03:48:00
【问题描述】:

根据Mongo Documentation

{ item : null } 查询匹配包含 item 字段,其值为 null 或不包含 item 字段。

我找不到这方面的文档,但据我所知,这两种情况(值是 null 或缺少字段)都以 null 的形式存储在索引中。

因此,如果我先执行db.orders.createIndex({item: 1}),然后执行db.orders.find({item: null}),我希望IXSCAN 可以找到包含item 字段且值为null 或不包含item 的所有文档字段,并且只有那些文档。

那么为什么db.orders.find({item: null}).explain() 在执行IXSCAN 之后在FETCH 阶段执行filter: {item: {$eq: null}}?可能需要过滤掉哪些可能的文档?

{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "temp.orders",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "item" : {
                "$eq" : null
            }
        },
        "winningPlan" : {
            "stage" : "FETCH",
            "filter" : {
                "item" : {
                    "$eq" : null
                }
            },
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "item" : 1
                },
                "indexName" : "item_1",
                "isMultiKey" : false,
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 1,
                "direction" : "forward",
                "indexBounds" : {
                    "item" : [
                        "[null, null]"
                    ]
                }
            }
        },
        "rejectedPlans" : [ ]
    },
    "serverInfo" : {
        "host" : "Andys-MacBook-Pro-2.local",
        "port" : 27017,
        "version" : "3.2.8",
        "gitVersion" : "ed70e33130c977bda0024c125b56d159573dbaf0"
    },
    "ok" : 1
}

我认为 undefined 的值可能会被索引为 null,但简单的实验排除了这一点:

> db.orders.createIndex({item: 1})
{
    "createdCollectionAutomatically" : true,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}
> db.orders.insert({item: undefined})
WriteResult({ "nInserted" : 1 })
> db.orders.find({item: {$type: 6}}).explain()
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "temp.orders",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "item" : {
                "$type" : 6
            }
        },
        "winningPlan" : {
            "stage" : "FETCH",
            "filter" : {
                "item" : {
                    "$type" : 6
                }
            },
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "item" : 1
                },
                "indexName" : "item_1",
                "isMultiKey" : false,
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 1,
                "direction" : "forward",
                "indexBounds" : {
                    "item" : [
                        "[undefined, undefined]"
                    ]
                }
            }
        },
        "rejectedPlans" : [ ]
    },
    "serverInfo" : {
        "host" : "Andys-MacBook-Pro-2.local",
        "port" : 27017,
        "version" : "3.2.8",
        "gitVersion" : "ed70e33130c977bda0024c125b56d159573dbaf0"
    },
    "ok" : 1
}

【问题讨论】:

    标签: mongodb null mongodb-query mongodb-indexes query-planner


    【解决方案1】:

    空相等匹配谓词(例如{"a.b": null})的语义非常复杂,因为字段可能包含子文档,仅靠索引扫描不足以提供正确的结果。

    根据https://jira.mongodb.org/browse/SERVER-18653?focusedCommentId=931817&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-931817

    服务器 2.6.0 版更改了空相等的语义 匹配谓词,使得文档 {a: []} 不再是 被认为是查询谓词 {"a.b": null} 的匹配项(之前 服务器的版本,此文档被认为与此匹配 谓词)。这记录在 2.6 兼容性说明中,位于 “空比较”部分。

    对于键模式为 {"a.b": 1} 的索引,此文档为 {a: []} 生成索引键 {"": null}。其他文档,例如 {a: null} 和 空文档 {} 还会生成索引键 {"": null}。作为一个 结果,如果带有谓词 {"a.b": null} 的查询使用此索引,则 查询系统不能仅从索引键 {"": null} 判断是否 关联的文档与谓词不匹配。因此, 分配 INEXACT_FETCH 界限而不是 EXACT 界限,因此 FETCH 阶段被添加到查询执行树中。

    补充说明:

    1. 文档 {} 为具有键模式 {"a.b": 1} 的索引生成索引键 {"": null}。
    2. 文档 {a: []} 还为具有键模式 {"a.b": 1} 的索引生成索引键 {"": null}。
    3. 文档 {} 匹配查询 {"a.b": null}。
    4. 文档 {a: []} 与查询 {"a.b": null} 不匹配。

    因此,查询 {"a.b": null} 由带有键的索引回答 模式 {"a.b": 1} 必须获取文档并重新检查谓词, 为了确保文档 {} 包含在结果集中 并且文档 {a: []} 不包含在结果集中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-15
      • 2015-09-17
      • 1970-01-01
      • 2016-04-16
      相关资源
      最近更新 更多