Mongodb 为什么在执行IXSCAN后,Mongo在FETCH中查询空过滤器

Mongodb 为什么在执行IXSCAN后,Mongo在FETCH中查询空过滤器,mongodb,null,mongodb-query,mongodb-indexes,query-planner,Mongodb,Null,Mongodb Query,Mongodb Indexes,Query Planner,根据, {item:null}查询匹配包含 item字段,其值为null或不包含项 场 我找不到这方面的文档,但据我所知,这两种情况(值为null或字段缺失)都以null的形式存储在索引中 因此,如果我执行db.orders.createIndex({item:1}),然后执行db.orders.find({item:null}),我将期望一个IXSCAN查找所有包含值为null的item字段的文档,并且只查找那些文档 那么为什么db.orders.find({item:null}).expla

根据,

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

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

因此,如果我执行
db.orders.createIndex({item:1})
,然后执行
db.orders.find({item:null})
,我将期望一个
IXSCAN
查找所有包含值为
null
item
字段的文档,并且只查找那些文档

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

{
    "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
}
我想,
未定义的
值可能会被索引为
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
}

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

根据,

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

对于键模式为{“a.b”:1}的索引,此文档为{a:[]} 生成索引键{“”:null}。其他文档,如{a:null}和 空文档{}还生成索引键{“”:null}。作为一个 结果,如果谓词为{“a.b”:null}的查询使用此索引,则 查询系统无法仅从索引键{“”:null}判断 关联文档与谓词不匹配。因此, 不精确的获取边界被指定,而不是精确的边界,因此 FETCH阶段添加到查询执行树中

补充说明:

  • 文档{}为键模式为{“a.b”:1}的索引生成索引键{“”:null}
  • 文档{a:[]}还为键模式为{“a.b”:1}的索引生成索引键{“”:null}
  • 文档{}与查询{“a.b”:null}匹配
  • 文档{a:[]}与查询{“a.b”:null}不匹配
  • 因此,一个查询{“a.b”:null}被一个带有key的索引所回答 模式{“a.b”:1}必须获取文档并重新检查谓词, 为了确保结果集中包含文档{} 并且结果集中不包括文档{a:[]}