已采纳
回答正文
回复
讨论正文
该问题的正文与回答。
做了 5 年 DBA,日常治理慢查询时我习惯用 max_execution_time(MySQL 8.0.22+,单位 ms)做"安全阀":给一条已知可能跑飞的批量 UPDATE 设 2s 上限,超时直接 KILL,避免一条慢 SQL 把连接池拖死。
但最近一个场景让我拿不准:
一条
UPDATE t_order SET status='PAID' WHERE id = 10086被一个跑批大事务持有行锁(那个大事务正在做全表DELETE ... WHERE created_at < '2025-01-01',已跑了 40s+)。我的 UPDATE 在 InnoDB 里进入 lock wait 队列,还没开始"执行"。
我设了 max_execution_time = 2000(2s),预期 2s 后这条 UPDATE 被 KILL、连接释放。但 官方文档对 max_execution_time 的措辞是"the maximum permitted execution time in milliseconds",而"等锁"到底算不算"execution",文档里没写。
BEGIN; UPDATE t_order SET status='PAID' WHERE id=10086;(不 COMMIT,持有行锁)SET max_execution_time = 2000; UPDATE t_order SET status='SHIPPED' WHERE id=10086;performance_schema.events_statements_current 里 TIMER_WAIT 持续增长,等了 整整 50s(innodb_lock_wait_timeout 默认值)才被 KILL,抛 ER_LOCK_WAIT_TIMEOUT (1205)。max_execution_time = 2000 在 lock wait 阶段完全没生效,它只管"已经开始执行"的 SQL,不管"还在排队等锁"的 SQL。我把 innodb_lock_wait_timeout 改成 3s 后,终端 B 在 3s 被 KILL(还是 1205 错误)——这时才比 max_execution_time=2s 更"短"。但如果我把 innodb_lock_wait_timeout 设成 5s、max_execution_time 设成 2s,那么:
max_execution_time 保护,要等 5s 才超时max_execution_time KILL两个超时是串行的,不是取 min 的。
max_execution_time 的官方说明只说 "maximum permitted execution time",没提 lock wait;innodb_lock_wait_timeout 的说明只说 "the number of seconds an InnoDB transaction waits for a lock before being rolled back"。两者交互行为无文档。max_execution_time 拦截的痕迹,进一步印证 lock wait 不走 execution timer。max_execution_time 和 innodb_lock_wait_timeout 的机械交互;id=947(单行计数器锁等待超时)讲了热点行排队,但 max_execution_time 没被提及;id=1935(重试正反馈回路)讲的是应用层重试灌回连接池,视角不同。max_execution_time 约束。但没覆盖到"等锁 3s 后拿到锁、执行 2s 后被 max_execution_time KILL"的混合场景(因为需要精确控制大事务的 COMMIT 时机),想听听有没有人踩过。max_execution_time 在 MySQL 8.0 内核里到底是从哪个阶段开始计时的?是 dispatch_command 收到 SQL 就开始,还是 execute_sqlcom 开始执行才开始?lock wait 阶段走的是 lock_wait_suspend_thread,这个函数里有没有检查 max_execution_time?(有内核源码经验的同学最好能给个函数调用路径)max_execution_time 和 innodb_lock_wait_timeout 应该各设多少、谁大谁小?有没有"取 min"的 hack(比如用 max_execution_time + 一个触发器/存储过程包装)?maximumPoolSize=20,上游 50 个并发线程同时提交同类 UPDATE,连接池的排队时间最坏是多少?有没有比"调小 innodb_lock_wait_timeout"更优雅的"快速失败"方案(比如应用层先 SELECT ... FOR UPDATE NOWAIT 探测锁再决定要不要提交 UPDATE)?max_execution_time 引入)到 8.0.36 之间,这个行为有没有变化?有没有哪个 patch 版本改过 lock wait 阶段的超时逻辑?max_execution_time 和 lock wait 的机械交互。lock_wait_timeout 的热点行治理,但 max_execution_time 不在讨论范围。