业务中需要统计一段时间投票独立的用户数,涉及到数组的排重,用传统array_unique()发现,当数据量达到百万级后, 设置的1G内存都耗尽了,仍然没有统计完。而用array_flip()发现不仅可以统计出来,而且更快。
之前这两种方式没有比较过,数据量小的时候也没有遇到问题,发现差异,一直混用。特记录下两种方式。
待排重的二维数组简化格式如下:
$date_uids = [ '20190201' => ['6367662430', '6367662430', '5304950359', '5955228171', '6557239611'], '20190202' => ['6367662430', '3699970002', '6619393423', '6026157677', '5476921392'], ];
方法一: 使用array_merge()结合array_unique()。
在遍历中array_merge()、array_unique()特别耗内存, 第9行,当以下count($uids) = 180万的时候,1G内存耗尽
// array_unique(); function distinct_uid_by_array_unique($datas) { $uids = []; foreach ($datas as $data) { if (empty($data)) { continue; } // 考虑先对$dara 使用array_unique()在合并。 $uids = array_unique(array_merge($uids, (array)$data)); } return count($uids); }
方法二:使用array_flip()和数组+合并。
去重总数为4572684,没有出现内存耗尽问题。
// array_flip(); function distinct_uid_by_array_flip($datas) { $uids = []; foreach ($datas as $data) { if (empty($data)) { continue; } $uids += array_flip($data); } return count($uids); }
以上都是直观感受,具体执行时间差异和内存占用差异,还有待对比。针对一维数组排重array_unique()和array_flip()比较,傲雪星枫有一组比较数据,array_flip方法去重比使用array_unique方法运行时间减少98%,内存占用减少4/5,可参考比较细节:《php 数组元素快速去重》
综上,在实际开发中,遇到排重的情况,优先使用array_flip(),尽量不考虑array_unique()。
完整示例:
$date_uids = [ '20190201' => ['6367662430', '6367662430', '5304950359', '5955228171', '6557239611'], '20190202' => ['6367662430', '3699970002', '6619393423', '6026157677', '5476921392'], '20190203' => ['6367662430', '5971792803', '5516939770', '6579480643', '6399312379'], ]; // array_unique(); function distinct_uid_by_array_unique($datas) { $uids = []; foreach ($datas as $data) { if (empty($data)) { continue; } $uids = array_unique(array_merge($uids, (array)$data)); } return count($uids); } // array_flip(); function distinct_uid_by_array_flip($datas) { $uids = []; foreach ($datas as $data) { if (empty($data)) { continue; } $uids += array_flip($data); } return count($uids); } $count = $total = 0; if (!empty($date_uids) && is_array($date_uids)) { $count = distinct_uid_by_array_unique($date_uids); $total = distinct_uid_by_array_flip($date_uids); } var_dump($count, $total);die; // 12 12
注:另外发现MySQL distinct有两种写发
select count(distinct(fan_uid)) from energy_fan_feed_0972; select count(distinct fan_uid) from energy_fan_feed_0972;