我有一台运行在具有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;满足我的好奇心)?
答案 0 :(得分:5)
这是预期的行为,请参阅:https://jira.mongodb.org/browse/SERVER-18653。看起来像是对我的一个奇怪的呼唤,但是你去了,我确信有些程序员比我更负责任地了解MongoDB。
您需要使用不同的值来表示null。我想这取决于你使用的字段。在我的例子中,它是一个外来引用,所以我只是开始使用false来表示null。如果您使用它来存储布尔值,那么您可能需要使用" null",-1,0等等。