MongoDB在计算空值时非常慢(或{$ exists:false})

And*_*lay 6 performance mongodb aggregation-framework

我有一台运行在具有16GB内存的VPS上的Mongo服务器(尽管可能使用磁盘的IO速度很慢).

我有大约3500万条记录的集合,这些记录不适合主内存(db.stats()报告size35GB和storageSize14GB),但报告的1.7GB记录totalIndexSize应该适合那里.

有一个特定的领域,bg我正在查询哪些可以存在有价值true或完全缺席(请不要讨论这是否是最好的数据表示 - 我仍然认为Mongo表现得很奇怪).此字段使用非稀疏索引编制索引,报告大小为146MB.

我正在使用具有默认缓存大小的WiredTiger存储引擎(所以它应该是大约8GB).

我正在尝试计算缺少该bg字段的记录数.

true数值相当快(几秒钟):

> db.entities.find({bg: true}).count()
8300677
Run Code Online (Sandbox Code Playgroud)

但是,对缺失值的查询非常慢(大约5分钟):

> db.entities.find({bg: null}).count()
27497706
Run Code Online (Sandbox Code Playgroud)

在我眼里,explain()看起来不错:

> db.entities.find({bg: null}).explain()
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "testdb.entities",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "bg" : {
                "$eq" : null
            }
        },
        "winningPlan" : {
            "stage" : "FETCH",
            "filter" : {
                "bg" : {
                    "$eq" : null
                }
            },
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "bg" : 1
                },
                "indexName" : "bg_1",
                "isMultiKey" : false,
                "direction" : "forward",
                "indexBounds" : {
                    "bg" : [
                        "[null, null]"
                    ]
                }
            }
        },
        "rejectedPlans" : [ ]
    },
    "serverInfo" : {
        "host" : "mongo01",
        "port" : 27017,
        "version" : "3.0.3",
        "gitVersion" : "b40106b36eecd1b4407eb1ad1af6bc60593c6105"
    },
    "ok" : 1
}
Run Code Online (Sandbox Code Playgroud)

然而,即使在重复呼叫之后,查询仍然非常缓慢.对不同值的其他计数查询很快:

> db.entities.find({bg: "foo"}).count()
0
> db.entities.find({}).count()
35798383
Run Code Online (Sandbox Code Playgroud)

我发现这种奇怪,因为我的理解是非稀疏索引中的缺失字段只是存储为null,所以计数查询null应该类似于计算实际值(或者可能是三次正数的三倍)值,如果它必须计算更多索引条目或其他东西).实际上,这个答案报告了相对于涉及null价值观的类似查询的速度提升.count().我能想到的唯一区别点就是WiredTiger.

任何人都可以解释为什么我的查询计算空值这么慢或我能做些什么来解决它(除了从true总数中明显减去计数,这将工作正常,但不能满足我的好奇心)?

msa*_*nce 5

这是预期的行为,请参阅:https://jira.mongodb.org/browse/SERVER-18653.看起来像是对我的一个奇怪的打电话,但是你去了,我确信有些程序员比我更了解MongoDB的责任.

您将需要使用不同的值来表示null.我想这取决于你使用的字段.在我的情况下,它是一个外来引用,所以我只是开始使用false来表示null.如果您使用它来存储布尔值,那么您可能需要使用"null",-1,0等.