当有数百万条记录时,Mongo计数真的很慢

时间:2012-03-19 21:43:49

标签: mongodb

//FAST
db.datasources.find().count()
12036788

//SLOW    
db.datasources.find({nid:19882}).count()
10161684

nid索引

任何方式使第二个查询更快? (大约需要8秒钟)

3 个答案:

答案 0 :(得分:26)

由于MongoDB仍然需要执行完整的b-tree walk以查找符合条件的适当数量的文档,因此计数查询(索引或其他方式)很慢。原因是MongoDB b-tree结构没有“计数”,这意味着每个节点都不存储有关节点/子树中元素数量的信息。

此问题在https://jira.mongodb.org/browse/SERVER-1752报告,除了手动维护该集合的计数器之外,目前还没有提高性能的解决方法,这显然会带来一些缺点。

另请注意,db.col.count()版本(因此没有条件)可以占用大的快捷方式,并且实际上不会执行查询,因此速度很快。也就是说它并不总是报告与计数查询相同的值,它应该返回所有元素(例如,它不会在具有高写入吞吐量的分片环境中)。争论是否是一个错误。我想是的。

请注意,在2.3+中引入了一个重要的优化,它应该(并确实)提高索引字段的计数性能。请参阅:https://jira.mongodb.org/browse/SERVER-7745

答案 1 :(得分:14)

正如@Remon所说,count()必须扫描与查询/过滤器匹配的所有文档。它是O(n),其中n是与索引匹配的文档数,如果字段未编入索引,则为集合中的文档数。

在这种情况下,您通常希望重新审视您的要求。你真的需要一个精确的数字10161684吗?如果精度很重要,则应为特定查询保留单独的计数器。

但在大多数情况下,精确度并不重要。这是两个中的一个:

  • 你不关心它是1000万还是1020万,但是数量级很重要,即你关心它是800万还是1000万。
  • 如果它是一个小的,你只关心精确的数字。即,您有兴趣知道有44个结果或72个。但是一旦超出1000个,您就可以说“找到超过1000个对象”。

在我的应用程序中,我发现第二个选项就是我想要的。因此,我也限制了count()查询,以便计数在达到限制时停止。像这样:

db.datasources.find({nid: 19882}).limit(1000).count(true)

对于用户,如果计数为1000,我会显示'1000 或更多结果',否则,我会显示确切的数字。

关于第一种选择......我还没有想到一个简洁的解决方案。

答案 2 :(得分:-1)

必须查看每个文档的每个字段。您可以索引nid以使计数更快。