【发布时间】:2015-01-12 08:38:41
【问题描述】:
我有一个 PHP 脚本,它在一个典型的循环中将来自 PDO 查询的“大型”数据集(大约 10 万条记录)处理成单个对象集合:
while ($record = $query->fetch()) {
$obj = new Thing($record);
/* do some processing */
$list[] = $obj;
$count++;
}
error_log('Processed '.$count.' records');
这个循环处理了大约 50% 的数据集,然后莫名其妙地中断了。
我尝试过的事情:
- 内存分析:
memory_get_peak_usage()在循环终止之前始终输出大约 63MB。内存限制为512MB,通过php.ini设置。 - 使用
set_time_limit()将脚本执行时间增加到1 小时(3600 秒)。循环在此之前很久就中断了,我在日志中没有看到此错误的常见错误。 - 将
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY设置为false以避免缓冲整个数据集 - 循环中断后立即注销
$query->errorInfo()。这没有帮助,因为错误代码是“00000”。 - 检查 MySQL 错误日志。在此脚本运行之前、之后或期间,其中没有任何值得注意的内容。
- 将处理批处理成 20K 记录块。没有不同。循环在同一个地方断裂。但是,通过在每批结束时“清理” PDO 语句对象,我能够将处理的总数提高到 54%。
其他奇怪的行为:
- 当我使用
ini_set('memory_limit', '1024MB')设置内存限制时,循环实际上比使用更小的内存限制提前终止,进度大约为 20%。 - 在此循环期间,PHP 进程使用 100% 的 CPU,但一旦中断,使用率会下降到 2%,尽管随后立即在另一个循环中进行处理。很可能,在第一个循环中与 MySQL 服务器的连接非常耗费资源。
如果这有什么不同的话,我会在本地使用 MAMP PRO 进行所有这些操作。
还有什么其他东西可以持续打破这个循环,我没有检查过吗?这难道不是处理这么多记录的可行策略吗?
更新
在使用批处理策略(20K 增量)后,我开始在第三批前后一直看到 MySQL 错误:MySQL server has gone away;可能是长时间运行的无缓冲查询的症状。
【问题讨论】:
-
如果您在浏览器上运行脚本,它会返回 500 内部服务器错误或白色空白页吗?您是否还在 php.ini 上打开了错误和警告?最近,当我尝试通过 php 将一个巨大的数据集从 xml 导入 mysql 时,发生了类似的事情。
-
@ADASein,正如我们所说的那样,我正在尝试一种批处理方法,但没有取得多大成功,将处理分成大约 20K 条记录的块。如果我确认这也不起作用,我会更新我的问题。
-
@HddnTHA,不,这不是内部服务器错误,
$query->fetch()未能在大约 50K 迭代点返回记录,因此while循环中断。 -
首先确保您启用了错误报告并且仍然没有记录错误(看起来就是这种情况)。如果发生这种情况,那么 PHP 进程会出现段错误,这是 a) 错误的指示,b) 不是您可以直接修复的问题。大多数情况下,这是由于 PHP 扩展中的一些错误造成的,但有时它也是核心。通常有解决方法。如果沿着这条路走下去,我建议在 Thing 构造函数中仔细查看任何不是沼泽标准 PHP 的东西。
-
使用 try..catch 块没有捕获任何异常?
标签: php mysql loops memory pdo