【发布时间】:2019-06-24 22:26:37
【问题描述】:
我对 PDO 很陌生 - 尝试优化一些以前一次更新 MySQL 表的代码,并让它改为批量更新,因为实际上有数千行。
长话短说,代码需要得到一个递归目录列表,并在此基础上更新文件url表,表明是否找到该表。这就是最终目标......这是代码执行的基本步骤:
- 清除“目录”表
- 对一个临时数组执行递归 scandir,数以千计的项目长
- 一一遍历数组,插入到“目录”表中
- 根据“目录”表的内容对主表设置文件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 端设置通用日志或慢查询日志,这样您就可以看到它们需要多长时间。