MongoDB在聚合查询方面的性能表现

28

听说MongoDB性能很好,于是我们决定尝试使用MongoDB来解决我们的问题。我开始将我们在几个MySQL数据库中拥有的所有记录移动到一个单独的MongoDB集合中。这导致了一个包含2900万个文档(每个文档至少有20个字段)的集合,占用约100 GB的硬盘空间。我们决定将它们全部放在一个集合中,因为所有文档的结构相同,我们希望对所有这些文档进行查询和聚合结果。

我创建了一些索引来匹配我的查询,否则即使是简单的count()也需要很长时间。然而,像distinct()和group()这样的查询仍然需要太长时间。

例子:

// creation of a compound index    
db.collection.ensureIndex({'metadata.system':1, 'metadata.company':1})

// query to get all the combinations companies and systems
db.collection.group({key: { 'metadata.system':true, 'metadata.company':true }, reduce: function(obj,prev) {}, initial: {} });

我查看了mongod日志,发现有很多类似这样的行(在执行上面的查询时):

Thu Apr  8 14:40:05 getmore database.collection cid:973023491046432059 ntoreturn:0 query: {}  bytes:1048890 nreturned:417 154ms
Thu Apr  8 14:40:08 getmore database.collection cid:973023491046432059 ntoreturn:0 query: {}  bytes:1050205 nreturned:414 430ms
Thu Apr  8 14:40:18 getmore database.collection cid:973023491046432059 ntoreturn:0 query: {}  bytes:1049748 nreturned:201 130ms
Thu Apr  8 14:40:27 getmore database.collection cid:973023491046432059 ntoreturn:0 query: {}  bytes:1051925 nreturned:221 118ms
Thu Apr  8 14:40:30 getmore database.collection cid:973023491046432059 ntoreturn:0 query: {}  bytes:1053096 nreturned:250 164ms
...
Thu Apr  8 15:04:18 query database.$cmd ntoreturn:1 command  reslen:4130 1475894ms

这个查询用了1475894毫秒,比我预期的要慢很多(结果列表大约有60条记录)。首先,考虑到我的集合中有大量文档,这种情况是否正常?通常在MongoDB中聚合查询是否会如此缓慢?您对如何提高性能有什么想法吗?

我在一台双核10GB内存的单机上运行mongod。

谢谢。


1
这个问题太老了,但是当你搜索MongoDB聚合框架时,它仍然会出现在搜索引擎中。Mario,你没有提到你的MongoDB版本,因为他们在2.4中大大改进了AF,我正在使用一台只有3.7G内存的糟糕m1.EC2处理包含6900万条数据的集合,速度比以前快得多。你尝试过新版本吗?还是采用了不同的方法?当然,有很多关于AF vs.MapReduce的基准测试,但请看一下10Gen最新的基准测试结果http://blog.mongodb.org/post/62900213496/qaing-new-code-with-mms-map-reduce-vs-aggregation谢谢。 - Maziyar
感谢您的评论。这是在2010年,我相信我们当时使用的是类似MongoDB 1.4.0的东西。已经过了一段时间,我相信自那时以来MongoDB已经发生了很多变化,但是自那年以后我就没有在那个项目上工作了 :) - Mario Duarte
谢谢Mario的回复。我刚开始使用MongoDB(大约一年),只是想知道你的项目进展如何。无论如何祝你好运 :) - Maziyar
3个回答

22

这个想法是在分布在多台机器上的分片数据库上使用MapReduce来提高聚合查询的性能。

我比较了Mongo的MapReduce和Oracle上的group-by-select语句在同一台机器上的性能。我发现Mongo大约慢了25倍。这意味着我必须将数据划分到至少25台机器上,才能使用Mongo获得与Oracle在单台机器上相同的性能。我使用了一个包含大约1400万个文档/行的集合/表。

通过mongoexport.exe从Mongo导出数据,将导出的数据作为外部表在Oracle中使用,并在Oracle中执行group-by操作比使用Mongo自己的MapReduce要快得多。


知道使用哪个版本的MongoDB会非常有帮助。 - nilskp
我相信它是类似于版本1.4.0的东西。那是在2010年。 - Mario Duarte

9

有几件事情:

1)您的组查询正在处理大量数据。虽然结果集很小,但看起来它正在对集合中的所有数据进行表级别的操作以生成这个小结果。这可能是缓慢的根本原因。为了加快速度,您可能需要查看查询运行时服务器的磁盘性能,可以通过iostat来实现,因为那很可能是瓶颈所在。

2)正如其他答案中指出的那样,group命令使用JavaScript解释器,这将限制性能。您可以尝试使用2.1版本中作为beta发布的新聚合框架(注意:截至2012年2月24日,这是不稳定的版本)。请参见http://blog.mongodb.org/post/16015854270/operations-in-the-new-aggregation-framework以获取良好的介绍。这不会克服(1)中的数据量问题,但它是用C ++实现的,如果javascript时间是瓶颈,则应该更快。

3)另一种方法是使用增量MapReduce生成第二个集合以获得分组结果。思路是运行一个MapReduce作业来聚合您的结果,然后定期运行另一个MapReduce作业,将新数据重新减少到现有集合中。然后,您可以从应用程序查询此第二个集合,而不是每次运行group命令。


6

在Mongo中,聚合(map reduce或其他方式)非常缓慢,因为它是由JavaScript虚拟机而不是数据库引擎执行的。这仍然是这个(我认为非常好的)数据库对时间序列数据的限制。


2
从v2.2版本开始,聚合管道使用本地操作 - Tamlyn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接