0:背景:
最近在做数据统计部分,数据是放在MongoDB的,我们一开始的方法是从MongoDB中将数据取出,在PHP中做运算,后面发现数据量大的时候,太慢了,120W的数据差不多要花30秒,后面实在受不了,于是打算使用MapReduce重构。
1:MapReduce:
$db->command([
'mapreduce' => 'orders',
'map' => 'function(){emit("money",this.money)}',
'reduce' => 'function(key, values){return Array.sum(values)}',
'query' => $map,
'out' => 'total_money'
]);
$re = $collection->selectCollection('total_money')->find();
但是用MapReduce后,性能提升不明显,目测只有10%左右。可能得益于省去网络的传输成本。
1.group(先筛选再分组,不支持分片,对数据量有所限制,效率不高)
2.mapreduce(基于js引擎,单线程执行,效率较低,适合用做后台统计等)
3.aggregate(推荐) (如果你的PHP的mongodb驱动版本需>=1.3.0,推荐你使用aggregate,性能要高很多,并且使用上要简单些,不过1.3的目前还不支持账户认证模式,可以通过http://pecl.php.net/package/mongo查看更新日志和Bug)
后面发现,楼主的mongodb驱动刚好好能用aggregate,所以果断使用aggregate。
2:aggregate
$collection->aggregate([
['$match' => $map],
['$group' => [
'_id' => null,
'total_money' => ['$sum' => '$money'],
'total_money_usd' => ['$sum' => '$money_usd']
]]
]);
由于楼主的MongoDB比较旧,所以不能再 $project 中调用 $sum(可以点我看看官方文档)。可以可贺的是,120w数据从原来的30秒下降到18秒,体验大大提升。领导看数据汇总也终于不用等半天了,下一步就是搞清楚分片以及升级一下MongoDB,看看有没有再提升的空间。