MongoDB聚合框架比Map/Reduce更快吗?

57

在MongoDB 2.2中引入的聚合框架,是否比map/reduce具有特殊的性能优势?

如果是的话,为什么、如何以及优化多少?

(我已经为自己进行了一次测试,性能几乎相同)


1
“几乎”相同?使用哪些基准进行比较?你的评论基本上毫无意义。而且你在比较猫和奶牛。此外,你自己也知道MR仍然限于单线程...所以:毫无意义的问题,因此评分为-1。 - user2665694
@user1833746 这是一个问题,我不想解释我的基准测试。我问这个问题是为了了解新的答案。请投票支持,以便其他人可以回答。 - Taha Jahangir
你看过这个问题(和答案)吗?https://dev59.com/tWfWa4cB1Zd3GeqPj7oS - Asya Kamsky
@Asya 是的,请看我的基准测试结果: - Taha Jahangir
1
请参考以下链接以便更好地理解相关内容: https://runnable.com/blog/pipelines-vs-map-reduce-to-speed-up-data-aggregation-in-mongodb - soheshdoshi
2个回答

66

我个人运行的每个测试(包括使用你自己的数据)都显示聚合框架比映射减少快几倍,并且通常快一个数量级。

只使用你发布的1/10数据(但不是清除操作系统缓存,而是先预热缓存 - 因为我想测量聚合表现,而不是读取数据所需时间),我得到了以下结果:

MapReduce:1,058毫秒
Aggregation Framework:133毫秒

去掉聚合框架中的$match和mapReduce中的{query:}(因为两者都只使用索引,这不是我们想要测量的),并将整个数据集按key2分组后,我得到了:

MapReduce:18,803毫秒
Aggregation Framework:1,535毫秒

这些非常符合我的以前的实验结果。


请参考以下内容,有关此事的更多评论请查看https://dev59.com/tWfWa4cB1Zd3GeqPj7oS - Asya Kamsky
感谢您回答了问题的第一部分!那第二部分呢?为什么和如何?您有什么补充吗?非常感谢您的任何意见。 - Jeach
1
这在文档中有详细介绍,但简而言之,聚合在服务器端(C++)本地运行,MapReduce会生成单独的JavaScript线程来运行JS代码。 - Asya Kamsky

9

我的基准测试:

== 数据生成 ==

使用 Python 生成 400 万行数据很容易,大约需要 350 字节。每个文档都有以下键:

  • key1,key2(两个随机列,用于测试索引,一个基数为 2000,另一个基数为 20)
  • longdata:用于增加每个文档的大小的长字符串
  • value:一个简单的数字(常数 10),用于测试汇总

db = Connection('127.0.0.1').test # mongo连接
random.seed(1)
for _ in range(2):
    key1s = [hexlify(os.urandom(10)).decode('ascii') for _ in range(10)]
    key2s = [hexlify(os.urandom(10)).decode('ascii') for _ in range(1000)]
    baddata = 'some long date ' + '*' * 300
    for i in range(2000):
        data_list = [{
                'key1': random.choice(key1s),
                'key2': random.choice(key2s),
                'baddata': baddata,
                'value': 10,
                } for _ in range(1000)]
        for data in data_list:
            db.testtable.save(data)
MongoDB 中的总数据大小约为 6GB(PostgreSQL 中约为 2GB)。

== 测试 ==

我做了一些测试,但只要比较结果就可以了:

注意:每次查询后,服务器都会重新启动,并清除操作系统缓存,以忽略缓存的影响。

查询:聚合所有 key1=somevalue 的行(约 20 万行),并为每个 key2 求和 value

  • map/reduce:10.6 秒
  • aggregate:9.7 秒
  • group:10.3 秒

查询:

map/reduce:

db.testtable.mapReduce(function(){emit(this.key2, this.value);}, function(key, values){var i =0; values.forEach(function(v){i+=v;}); return i; } , {out:{inline: 1}, query: {key1: '663969462d2ec0a5fc34'} })

aggregate:

db.testtable.aggregate({ $match: {key1: '663969462d2ec0a5fc34'}}, {$group: {_id: '$key2', pop: {$sum: '$value'}} })

group:

db.testtable.group({key: {key2:1}, cond: {key1: '663969462d2ec0a5fc34'}, reduce: function(obj,prev) { prev.csum += obj.value; }, initial: { csum: 0 } })


4
"group"不是聚合框架,它是Map/Reduce的一部分,因此具有reduce函数。请参见以下链接以了解其差异:http://docs.mongodb.org/manual/reference/command/group/ 和http://docs.mongodb.org/manual/reference/aggregation/#_S_group。如果您正在使用聚合框架,则需要调用db.collection.aggregate([pipeline])。 - Asya Kamsky
我有一个建议:为什么不将查询语句删除,对整个集合运行相同的操作,看看性能是否有所差异。 - Asya Kamsky
4
你的基准测试还存在另一个问题,你清除了操作系统缓存?这样你测量的大部分时间都是将数据换入RAM所需的时间。这使得实际性能数字相形见绌,而且并不是一个现实的场景。 - Asya Kamsky

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