处理部分大型数据集后,PHP PDO fetch() 循环终止

标签 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');

这个循环处理了大约 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 记录 block 。没有不同。环路在同一个地方断了。但是,通过在每批结束时“清理”PDO 语句对象,我能够将处理总数提高到 54%。

其他奇怪的行为:

  • 当我使用 ini_set('memory_limit', '1024MB') 设置内存限制时,循环实际上比使用更小的内存限制(大约 20)更早结束% 进度。
  • 在此循环中,PHP 进程使用 100% 的 CPU,但一旦中断,使用率会回落至 2%,尽管随后会立即在另一个循环中进行处理。很可能,在第一个循环中与 MySQL 服务器的连接非常耗费资源。

如果有任何不同,我将使用 MAMP PRO 在本地完成所有这些工作。

有没有其他我没有检查过的东西可以持续打破这个循环?这根本不是处理这么多记录的可行策略吗?

更新

在使用批处理策略(20K 增量)后,我开始在第三批左右看到一个 MySQL 错误:MySQL server has gone away;可能是长时间运行的无缓冲查询的症状。

最佳答案

如果您真的需要即时处理 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');

此外,仅选择您将使用的行。 如果这没有帮助,您可以试试这个:Setting a connect timeout with PDO .

关于处理部分大型数据集后,PHP PDO fetch() 循环终止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26938728/

相关文章:

c - 使用 EOF 循环打印最小值和最大值

c++ - 如何检查 a^b == c^d 是否。我面临的问题是循环的速度。我已经优化了寻找指数的部分

php - 如何检测损坏的图像并替换为另一个图像?

php - LINES TERMINATED BY 和 FIELDS TERMINATED BY 的多种可能性 - MySQL

php - 内连接表时执行删除

php - 排除在搜索结果中首先获取的结果

c - 在 C 中使用 do while 循环时遇到问题

php mysql 在 SELECT 语句中添加 *

php - MySQL 数据库未填充

php - 使用 psr-4 命名空间失败