whereIn 大数据,内存占用问题
// 取 order 表的部分符合条件的 uuid ,此处为简单示例直接取 all
$orderUUIDs = Order::all()->pluck('order_uuid');
info('内存记录:'.memory_get_usage());
// 代码执行到下面这句内存溢出,实际使用时 $orderUUIDs 大概有十几万条
OrderFee::whereIn('order_uuid', $orderUUIDs)->sum('fee');
以上代码输出
[2022-07-27 18:36:02] production.INFO: 内存记录:51784224
[2022-07-27 18:36:02] production.ERROR: Allowed memory size of 134217728 bytes exhausted (tried to allocate 1052672 bytes) {"exception":"[object] (Symfony\\Component\\ErrorHandler\\Error\\FatalError(code: 0): Allowed memory size of 134217728 bytes exhausted (tried to allocate 1052672 bytes) at /apps/storage/20220720181003/vendor/laravel/framework/src/Illuminate/Collections/Arr.php:558)
问题:MySQL in 怎么这么耗内存,我只是取一个聚合结果
$orderUUIDs 大概有十几万条 php不内存溢出 、sql长度设置小了 语句也会执行不了 、wherein 十几万意义在哪
如果用子查询呢
如果有联合索引还好点,没索引全表扫描了
一条SQL可以完成的没必要拆开来写,建议用Join连接查询
这是架构设计上的问题了,这些数据可以通过定时任务或消息队列中去分析,这样可以将查询的任务拆分,不至于影响到其他业务。亦或是通过 MQ 将数据写入支持 OLAP 的一些数据库,如 Clickhouse。
wherein 如果数据过大 还是用join把,不然你那么多数据传过去 mysql的tcp都顶不住
按照楼主描述 数据查出来十几万条数据, 楼层有人回答索引的问题, 殊不知在
in
一个非常大的范围的时候, 索引会无效. 我相对会建议chunk
+索引
.这是php内存爆了,不是mysql内存爆了。看情况mysql是返回了数据的。
建议 join
这种大批量的数据建议不要在服务中实时计算,耗时太严重,可以通过定时任务刷新数据到缓存中,服务直接读取缓存中的数据
OrderFee
先与Order
建立模型关系,在使用whereHas
进行查询。chunk
分段in
优化
之所以转成原生
DB
,是因为model
很占用内存。问题
这个错误属于
php
层Order::all()->pluck('order_uuid')
(就算是为了演示,也不能这么写啊
Order::pluck('order_uuid')
都比这个好十万条数据,就是10万个类
ps:我感觉不是
whereIn
问题,因为不科学。奇奇怪怪的设计
where in 十几万太多了,建议数据写到统计表,查起来就快了。
用子查询,这样不用取到PHP的内存里,然后PHP里用迭代器
优化一:
优化二:
定义为Command/消费金额统计命令,然后注册到任务调度里面去统计。
如果你直接实时的话,很容易阻塞worker进程无法响应nginx。
也可以使用chunkById这种方式,区别在于这种类似于命令行分页查询, where id > xxx limit 500运行。