PHP PDO fetch()循环在处理部分大数据集后死亡
我有一个PHP脚本,它将PDO查询中的一个“大”数据集(大约100K条记录)处理为一个对象集合,在一个典型的循环中:PHP PDO fetch()循环在处理部分大数据集后死亡,php,mysql,loops,memory,pdo,Php,Mysql,Loops,Memory,Pdo,我有一个PHP脚本,它将PDO查询中的一个“大”数据集(大约100K条记录)处理为一个对象集合,在一个典型的循环中: while ($record = $query->fetch()) { $obj = new Thing($record); /* do some processing */ $list[] = $obj; $count++; } error_log('Processed '.$count.' records'); 这个循环处理大约5
while ($record = $query->fetch()) {
$obj = new Thing($record);
/* do some processing */
$list[] = $obj;
$count++;
}
error_log('Processed '.$count.' records');
这个循环处理大约50%的数据集,然后莫名其妙地中断
我尝试过的事情:
- 内存分析:
在循环结束之前始终输出大约63MB的内存。内存限制为512MB,通过php.ini设置Memory\u get\u peak\u usage()
- 使用
将脚本执行时间增加到1小时(3600秒)。循环在此之前很久就中断了,我在日志中看不到这个循环的常见错误设置时间限制()
- 将
设置为PDO::MYSQL\u ATTR\u使用\u BUFFERED\u QUERY
,以避免缓冲整个数据集false
- 循环中断后立即注销
。这没有帮助,因为错误代码是“00000”$query->errorInfo()
- 正在检查MySQL错误日志。在脚本运行之前、之后或期间,没有任何值得注意的内容
- 将处理批处理为20K个记录块。没有区别。环路在同一个位置断开。然而,通过在每个批处理结束时“清理”PDO语句对象,我能够使处理的总数达到54%
- 当我使用
设置内存限制时,循环实际上比使用较小内存限制的循环更早结束,大约有20%的进度ini\u set('memory\u limit','1024MB')
- 在这个循环过程中,PHP进程使用100%的CPU,但一旦中断,使用率就会下降到2%,尽管随后会立即在另一个循环中进行处理。很可能,在第一个循环中与MySQL服务器的连接非常占用资源
在使用批处理策略(20K增量)后,我开始在第三批前后一致地看到一个MySQL错误:
MySQL服务器已经消失了
;可能是长时间运行的无缓冲查询的症状。如果您真的需要动态处理100K条记录,则应使用SQL进行处理,并根据需要获取结果-这将节省大量时间
但由于某些原因,你可能无法做到这一点。您总是处理语句中的所有行,所以只需使用fetchAll一次,之后就不用管MySQL了,如下所示:
$records = $query->fetchAll()
foreach ($records as record)
{
$obj = new Thing($record);
/* do some processing */
$list[] = $obj;
$count++;
}
error_log('Processed '.$count.' records');
此外,仅选择要使用的行。
如果这不起作用,您可以尝试以下方法:。如果您在浏览器上运行脚本,它是否返回500内部服务器错误或白色空白页?您是否在php.ini上打开了错误和警告?最近,当我试图通过php将一个巨大的数据集从xml导入mysql时,类似的事情发生在我身上。@ADASein,正如我们所说的,我正在尝试一种批处理的方法,将处理过程分为大约20K条记录。如果我确认这也不起作用,我将更新我的问题。@HddnTHA,不,这不是一个内部服务器错误,
$query->fetch()
无法在大约50K的迭代点返回记录,因此while
循环中断。首先确保启用了错误报告,并且仍然没有记录错误如果发生这种情况,那么PHP进程会出现错误,这是a)缺陷的指示,b)不能直接修复。大多数情况下,这是由于PHP扩展中的一些错误造成的,但有时这也是核心问题。通常有变通办法。如果沿着这条路走下去,我建议仔细检查一下Thing构造函数中不是bog标准PHP的东西。使用try..catch块不捕获任何异常?