我的PHP 7.4脚本从本地MySQL 5.7数据库中选择一个大型InnoDB表,并使用PDO迭代每一行。我使用无缓冲查询的目的是因为整个表将无法容纳服务器内存。
查询是一个简单的SELECT * FROM table WHERE field_a = ... ORDER BY field_b, field_c
。
迭代结果的代码为:
$rows = $db->prepare('redacted');
$rows->bindParam(':redacted', $redacted);
$rows->execute();
foreach($rows as $r) {
if($r->fieldname != redacted)
doWork1();
doWork2();
}
doWork2()
,它始终使用单独的缓冲PDO连接执行以下工作:
1.更新数据库上的行;
1.在事务中,在另一个表中插入较少新行(每行一个INSERT查询)。
每次迭代花费的时间不会超过1-2秒,但整个循环可能需要几个小时才能完成。
脚本运行良好,但是正好每12:00分钟,PDO抛出以下异常:
[03-Feb-2023 08:34:29 Europe/Rome] PHP Fatal error: Uncaught PDOException: SQLSTATE[HY000]: General error: 2006 MySQL server has gone away in redacted:176
Stack trace:
redacted
[03-Feb-2023 08:46:50 Europe/Rome] PHP Fatal error: Uncaught PDOException: SQLSTATE[HY000]: General error: 2006 MySQL server has gone away in redacted:176
Stack trace:
redacted
行号总是foreach或if。
博客说:
2023-02-03T08:36:33.480661+01:00 781575 [Note] Aborted connection 781575 to db: 'redacted' user: 'redacted' host: 'localhost' (Got timeout writing communication packets)
2023-02-03T08:48:56.534865+01:00 781768 [Note] Aborted connection 781768 to db: 'redacted' user: 'redacted' host: 'localhost' (Got timeout writing communication packets)
在重新启动脚本时,它可以在相同的数据上正常工作,因此值或数据类型没有问题。mysqladmin version
显示服务器从未崩溃。
我想这是由于某种超时。
我注意到mysql日志中的时间戳大约是PHP致命错误发生后2分钟,所以写超时导致的断开连接是结果,而不是原因。因此,增加net_read_timeout
和net_write_timeout
(120秒),wait_timeout
(8小时),max_allowed_packet
(256 MB)没有帮助。我仔细检查了所有服务器变量,没有任何值接近12分钟或720秒。
查询速度快(不到3秒钟)并经过优化;没有大的田野;它使用索引;查询EXPLAIN是(相关部分):594802 | 5.67 | Using index condition; Using where; Using filesort
。我不在https://dev.mysql.com/doc/refman/8.0/en/gone-away.html中提到的情况下
该机器是装有Linux和cPanel的AWS Lightsail。
# mysqladmin version
mysqladmin Ver 8.42 Distrib 5.7.40, for Linux on x86_64
redacted
Uptime: 10 days 10 hours 34 min 13 sec
redacted
Threads: 6 Questions: 15310531 Slow queries: 0 Opens: 9989 Flush tables: 1 Open tables: 1854 Queries per second avg: 16.972
我启用了查询日志,并仔细检查了错误时间,所有查询都是正确的。
1条答案
按热度按时间2jcobegt1#
当我能够如此容易地复制这个时,我感到很惊讶。我创建了三个独立的PDO连接到我的数据库服务器-
1.对于无缓冲查询
1.运行常规调用以检查处理无缓冲查询的线程的状态
1.根据从无缓冲查询中读取的行运行更新
在没有做任何配置更改的情况下,处理无缓冲查询的线程在16分钟后被服务器关闭。我在会话变量中找不到任何提示超时为16分钟的内容。
我的解决方案是增加net_write_timeout的长度,使其足够长,以便逐行获取整个未缓冲的结果。我将其增加到30分钟、60分钟,然后是2小时。每次未缓冲的查询结果的连接都保持打开,直到指定的超时过去(1 - 6分钟后)。
然后我把它设置为36000(10小时),它现在已经运行了4个多小时-
我怀疑使用较小的缓冲查询(行数取决于平均行大小)从源表中选择数据比连续几个小时为无缓冲查询保持此连接打开更好。
我最近看到的唯一一篇讨论无缓冲查询和net_write_timeout效果的文章是this one by Hayden James,它只是顺便提到net_write_timeout。