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

时间:2015-05-19 07:55:58

标签: performance mongodb aggregation-framework

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

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

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

我使用带有默认缓存大小的WiredTiger存储引擎(因此应该大约为8GB)。

我试图计算缺少bg字段的记录数。

计算true值的速度相当快(几秒钟):

> db.entities.find({bg: true}).count()
8300677

然而,缺失值的查询非常慢(大约5分钟):

> db.entities.find({bg: null}).count()
27497706

在我看来,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
}

然而,即使经过多次调用,查询仍然非常缓慢。对不同值的其他计数查询很快:

> db.entities.find({bg: "foo"}).count()
0
> db.entities.find({}).count()
35798383

我觉得这很奇怪,因为我的理解是非稀疏索引中缺少的字段只是存储为null,所以带null的计数查询应该类似于计算实际值(或者,如果必须计算更多的索引条目或其他东西,则可能最多三次为正值的三倍)。实际上,this answer报告涉及null值和.count()的类似查询的速度大幅提升。我能想到的唯一区别点就是WiredTiger。

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

1 个答案:

答案 0 :(得分:5)

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

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