php循环处理6万条数据性能优化问题

时间:2022-09-20 23:28:26
如下代码,这是服务器上的一个脚本文件的。变量$productList里取出的表erp_products_data里的数据,有6万多条,也就是我的foreach循环要跑6万多次,而循环里面,还要处理3个查询sql,1个更新sql,循环万总计跑了24万多sql才结束。这样的结果是慢。我自己的思路是把sql拆分处理,因为一次性处理6万多数据非常慢的话,对内存是一个极大的影响,这问题可能还有其他优化方案,所以问问各位老哥们优化的方法。
注:1. foreach里面的查询无法取出一次性处理,复杂性会更大,性能不会太好
         2. 这是一个全表扫的sql,需要计算每一个行的某个字段的值,每天都需要计算


$productList = $productsManage->getAllActiveProductList($fields, $params);
//print_r($productList);exit;
if (empty($productList)){
die('没有获取到产品信息');
}

$table = "erp_products_data";
$i = 0;
//开始循环来计算吧
foreach ($productList as $pro){

//SKU
$sku       = trim($pro['products_sku']);
$warehouse = $pro['product_warehouse_id'];
$id        = $pro['products_id'];

//计算利润率
$avgProfitRate = $getTotals->getSkuFiveAverage($sku);

//计算60天退款次数
$skuMoneybackCount = getSkuMoneybackCount($sku);

//计算各仓库的60天销量
$sold_60 = getSalesTotalInSalesRecordMinDays($sku, 60 ,$v['product_warehouse_id']);

$data                  = array();
$data['sold_60']       = $sold_60;
$data['backMoney_60']  = $skuMoneybackCount;
$data['profitRate_15'] = $avgProfitRate;

$where = " products_id=".$id;
$doSql->update($table, $data, $where);
if($i>100){
$end_time = microtime(true);
$ret_time = $end_time - $start_time ;
echo "Code execution time is ".$ret_time." second";
echo 'the end...';
exit;
}
$i++;
}

12 个解决方案

#1


目前我是把他拆分开  跑4次  性能还是不行

#2


php循环处理6万条数据性能优化问题

#3


$data['sold_60']       = $sold_60;
$data['backMoney_60']  = $skuMoneybackCount;
$data['profitRate_15'] = $avgProfitRate;
这三个量是如何计算的?
瓶颈应该在这里

#4


问题的话按理来说肯定是出现在这几个变量的计算,所以我本地测试了一下,跑100条数据的时候耗时是 6.9323971271515,这性能也不想说了,代码是前人写的。也就是1000条需要70秒,10000条需要1个小时这样   4个线程的话也是这样计算   但是问题是  我本地测试没有问题  虽然会慢一点  线上服务器发生了一个问题  死锁  这搞得比较纠结   所以这块得急需优化一下  但是问题是  
$data['sold_60']       = $sold_60;
$data['backMoney_60']  = $skuMoneybackCount;
$data['profitRate_15'] = $avgProfitRate;
这三个的计算消耗的速度性能还可以..

#5


提供两个方案吧
1、改为触发式的更新,不用每天都集中在同一个时间段统计。若是这个产品被读取出来显示了(不管是列表还是详情之类的,看你业务需求),并且今天还没有更新过(可在 erp_products_data 表设置一个字段来标识),就执行统计更新,最好是异步

2、改为异步并发统计,就像你设置crontab 一样,只是这是代码层上的,一个分发页面,一个执行页面,执行页面接收来自分发页面的参数,从哪里开始执行统计,可以异步发起多个执行请求(10个,20个,随你)

#6


这三个量在计算时只传递了简单的参数,而这三个量都与历史数据有关(都是统计值)
你不去考究他们的算法,就想当然的说 性能还可以。是很不严肃的

#7


@xuzuning
目前来看  版主的考虑是对的  这块可以改为批量更改就能解决  

@jam00这位朋友的也是很好的  监听触发 异步队列执行,可以代码上来监听,也可以写个触发器监听。业务上来看,这块触发的地方有点多,代码监听可能不太适合,触发器监听应该会比较好 不过这块最好不写触发器 所以我考虑版主的批量进行试一下  性能应该会好很多

#8


1.如果数据量很大, 可以用计划任务去跑,如果实时性要求不是很高。
2.开启多个线程去处理数据,这样在速度上有提高。

#9


目前是crontab开了4个线程跑的

#10


如果没有大量 I/O 操作,多线程要比单线程还慢!

#11


1.看看查询的,对查询字段都加了索引
2.更新可以把多条更新语句先保存,然后批量更新,这样可以减少锁表开锁时间
3.相同的product估计数据是一样的,可以先把所有product放入cache,使用时直接从cache读取,减少连接数据库操作。
4.更新涉及锁表,所以多线程都是需要等待的。

#12


触发式好一些,有人看的时候再计算,今天计算过的不用再次计算
但如果你想搞排名就不行了,把6W多条数据拆开来一点点处理

#1


目前我是把他拆分开  跑4次  性能还是不行

#2


php循环处理6万条数据性能优化问题

#3


$data['sold_60']       = $sold_60;
$data['backMoney_60']  = $skuMoneybackCount;
$data['profitRate_15'] = $avgProfitRate;
这三个量是如何计算的?
瓶颈应该在这里

#4


问题的话按理来说肯定是出现在这几个变量的计算,所以我本地测试了一下,跑100条数据的时候耗时是 6.9323971271515,这性能也不想说了,代码是前人写的。也就是1000条需要70秒,10000条需要1个小时这样   4个线程的话也是这样计算   但是问题是  我本地测试没有问题  虽然会慢一点  线上服务器发生了一个问题  死锁  这搞得比较纠结   所以这块得急需优化一下  但是问题是  
$data['sold_60']       = $sold_60;
$data['backMoney_60']  = $skuMoneybackCount;
$data['profitRate_15'] = $avgProfitRate;
这三个的计算消耗的速度性能还可以..

#5


提供两个方案吧
1、改为触发式的更新,不用每天都集中在同一个时间段统计。若是这个产品被读取出来显示了(不管是列表还是详情之类的,看你业务需求),并且今天还没有更新过(可在 erp_products_data 表设置一个字段来标识),就执行统计更新,最好是异步

2、改为异步并发统计,就像你设置crontab 一样,只是这是代码层上的,一个分发页面,一个执行页面,执行页面接收来自分发页面的参数,从哪里开始执行统计,可以异步发起多个执行请求(10个,20个,随你)

#6


这三个量在计算时只传递了简单的参数,而这三个量都与历史数据有关(都是统计值)
你不去考究他们的算法,就想当然的说 性能还可以。是很不严肃的

#7


@xuzuning
目前来看  版主的考虑是对的  这块可以改为批量更改就能解决  

@jam00这位朋友的也是很好的  监听触发 异步队列执行,可以代码上来监听,也可以写个触发器监听。业务上来看,这块触发的地方有点多,代码监听可能不太适合,触发器监听应该会比较好 不过这块最好不写触发器 所以我考虑版主的批量进行试一下  性能应该会好很多

#8


1.如果数据量很大, 可以用计划任务去跑,如果实时性要求不是很高。
2.开启多个线程去处理数据,这样在速度上有提高。

#9


目前是crontab开了4个线程跑的

#10


如果没有大量 I/O 操作,多线程要比单线程还慢!

#11


1.看看查询的,对查询字段都加了索引
2.更新可以把多条更新语句先保存,然后批量更新,这样可以减少锁表开锁时间
3.相同的product估计数据是一样的,可以先把所有product放入cache,使用时直接从cache读取,减少连接数据库操作。
4.更新涉及锁表,所以多线程都是需要等待的。

#12


触发式好一些,有人看的时候再计算,今天计算过的不用再次计算
但如果你想搞排名就不行了,把6W多条数据拆开来一点点处理