【问题标题】:PDO transaction timing out when it has 10 insert (to mysql) statementsPDO 事务在有 10 个插入(到 mysql)语句时超时
【发布时间】:2019-06-24 22:26:37
【问题描述】:

我对 PDO 很陌生 - 尝试优化一些以前一次更新 MySQL 表的代码,并让它改为批量更新,因为实际上有数千行。

长话短说,代码需要得到一个递归目录列表,并在此基础上更新文件url表,表明是否找到该表。这就是最终目标......这是代码执行的基本步骤:

  1. 清除“目录”表
  2. 对一个临时数组执行递归 scandir,数以千计的项目长
  3. 一一遍历数组,插入到“目录”表中
  4. 根据“目录”表的内容对主表设置文件foundstatus运行更新查询

第 3 步是我遇到问题的地方。我不断收到“PHP 致命错误:超过 90 秒的最大执行时间”。我已将事务大小减少到 10,并将 max_execution_time 增加到 90,并且它确实在因上述错误而崩溃之前插入了 1720 行。

这是第 3 步的代码(包括第 2 步的一些代码) - $pdo 是一个 PDO 对象。如果有人有任何指示,将不胜感激。 :)

//get the dir list into a one-dimensional array
$dirlistall = scanAllDir($rootdirprefix . 'docs/sds');
$countDirsList = count($dirlistall);
//print_r($dirlistall);

//load the dir list into the Directory Listings table
$stmt = $pdo->prepare("INSERT INTO DirectoryListingResults (URL) VALUES (:url)");
$batchSize = 10;
$i = 0;
try {
    for ($idx=0; $idx*$batchSize < $countDirsList; $idx++) { 
        $dirsPartial = array_slice($dirlistall, $idx*$batchSize, $batchSize);

        $pdo->beginTransaction();
        $stmt->bindParam(':url', $url);
        foreach ($dirsPartial as $url)
        {
            $stmt->execute();
        }
        $pdo->commit();

        unset($dirsPartial);
    }
}catch (Exception $e){
    $pdo->rollback();
    throw $e->getMessage();
}
unset($dirlistall);

在我的测试机器上运行代码,该机器运行带有 IIS 的 Windows 10 和 PHP 5.6。 MySQL 服务器是远程的,版本 5.6.43。

[编辑]:如果相关,这里是 PDO 连接选项:

$pdooptions = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES   => false,
];

【问题讨论】:

  • 你试过没有交易吗?内部foreach 循环运行了多少次?外部的for 循环呢?
  • 我真的不能说,因为这是一个 PHP 崩溃,所以我不能让它抛出更多信息,但是从数学开始(每批 10 行,它成功添加了 1720 行在崩溃之前),它似乎运行了 172 次。 $dirlistall 中应该有 29,329 个项目。没有交易没试过。有点害怕。 :)
  • 更新:在没有事务的情况下,它成功添加了 1882 行,然后崩溃并出现相同的错误。
  • 这不是“崩溃”,而是超时。所以,增加你的超时时间并调整你的 MySQL 设置,让它更有效地运行。在 DB 端设置通用日志或慢查询日志,这样您就可以看到它们需要多长时间。

标签: php mysql pdo


【解决方案1】:

我很好奇绑定值而不是参数是否有帮助,所以用这个代替

$stmt->bindParam(':url', $url);
foreach ($dirsPartial as $url)
{
    $stmt->execute();
}

这个

foreach ($dirsPartial as $url)
{
    $stmt->execute([':url' => $url]);
}

我真的不知道这是否有助于提高性能,但我知道由于参数受引用绑定,所以在 foreach 循环中重新定义 $url 通常会导致问题。

【讨论】:

  • 这也是我的评论(加上“我不知道这是否会有所帮助”的警告。)
  • @miken32 实际上我犹豫是否要添加它作为答案,但我无法弄清楚如何在评论中清楚地说明它。
  • 感谢您的建议 - 我不知道 bindParam 不能正常工作。不幸的是,它似乎没有任何区别(并且可能让事情变得更糟 - 这一次,它设法在崩溃之前插入 1680 行,而在它之前是 1720)。
猜你喜欢
  • 1970-01-01
  • 2017-09-05
  • 2015-02-12
  • 2013-11-03
  • 2013-05-15
  • 2020-04-18
  • 2014-08-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多