使用SQLAlchemy+PyMySQL时read_timeout参数无效的原因排查
你遇到的问题是因为read_timeout的作用范围和你预期的不一致,还有几个细节因素导致超时未触发,具体原因如下:
read_timeout仅监控数据读取阶段,不包含服务器查询执行时间
PyMySQL的read_timeout是指MySQL服务器开始返回数据后,客户端等待接收数据的超时时间,而非从发送查询请求开始的总耗时。如果复杂查询在MySQL服务器上需要运行几分钟才能生成结果,这个阶段客户端只是处于等待状态,并没有在读取数据,所以read_timeout不会触发。连接池复用了未配置超时的旧连接
SQLAlchemy默认使用连接池,如果应用启动时创建的连接没有设置read_timeout,或者连接池中的旧连接是在你添加connect_args之前创建的,复用这些连接时就不会有超时限制。这种情况下,需要清空连接池(比如重启应用,或者调用engine.dispose()),让新创建的连接带上超时参数。PyMySQL旧版本存在实现缺陷
部分早期版本的PyMySQL对read_timeout的处理有bug,无法正确监控服务器执行查询时的空闲等待状态,导致超时机制失效。建议升级到最新稳定版的PyMySQL(比如>=1.0.0版本)后再测试。MySQL服务器端超时配置覆盖客户端设置
如果MySQL服务器端设置了wait_timeout或interactive_timeout,且数值远大于你的read_timeout,当连接处于等待服务器执行查询的空闲状态时,服务器不会主动断开连接,客户端的read_timeout也因无数据传输不会触发。这种情况可以结合调整服务器端参数或其他方案解决。
另外,如果你需要限制查询的总执行时间(含服务器执行阶段),仅靠PyMySQL的read_timeout无法实现,可在SQL语句中使用MySQL 5.7+支持的MAX_EXECUTION_TIME强制终止超时查询:
SELECT /*+ MAX_EXECUTION_TIME(2000) */ * FROM your_table WHERE ...;
内容的提问来源于stack exchange,提问作者ascripter

