已采纳
回答正文
回复
讨论正文
该问题的正文、回答与讨论。
主库 MySQL 8.0.36(云 RDS,32C128G),核心表 t_settle_record 约 2.1 亿行,InnoDB,RR 隔离。白天 QPS 约 3500(混合读写),凌晨 02:00 有批跑任务集中写入。
之前遇到过「统计信息漂移导致执行计划翻转」的问题(我写过一篇总结,见引用),后来 DBA 把 innodb_stats_auto_recalc = ON 留着,让 InnoDB 在数据量变化超过 10% 时自动重采样。
最近一周观察到:凌晨 02:1x 到 02:4x 之间,t_settle_record 上的 INSERT 出现 30~50s 的阻塞尖峰(SHOW PROCESSLIST 里状态是 Waiting for table metadata lock),同一时间窗口其他表(t_user、t_order)的 INSERT 完全正常。
我怀疑这是 ANALYZE TABLE(自动触发的手动重采样)拿了该表的 MDL 排他锁,把并发的 DML 全部挡住。但我不确定:
ANALYZE TABLE 在 InnoDB 里到底需要 MDL 排他锁还是共享锁?8.0 的源码路径是 mysql/analyze_table.cc,但实际拿的是 MDL_SHARED 还是 MDL_EXCLUSIVE?t_settle_record 而不动其他表?(我理解 MDL 是表粒度的,这个符合预期,但想确认 8.0 没有"按索引粒度"的 MDL)innodb_stats_auto_recalc 触发)和手动 ANALYZE TABLE 拿的锁级别是否一致?SET GLOBAL innodb_stats_auto_recalc = OFF,改完后执行计划漂移问题回来了(白天某些租户查询从走索引退化成全表扫描);ANALYZE TABLE t_settle_record,还是撞上 DML(因为 01:00 也有少量写入);ANALYZE TABLE ... PERSISTENT:8.0.36 不支持 PERSISTENT 子句(那是 8.1+ 的语法);pt-online-schema-change:试过,但那是 DDL 工具,对 ANALYZE 无效;information_schema.innodb_table_stats 直接看:能看到 n_diff_pfx1/2/3 的采样值,但看不到"采样过程中是否持锁";performance_schema.metadata_locks:在阻塞窗口抓了快照,确实看到 t_settle_record 上有一条 OBJECT_TYPE=TABLE, OBJECT_NAME=t_settle_record, LOCK_TYPE=EXCLUSIVE, LOCK_DURATION=TRANSACTION, OWNER_THREAD_ID=<ANALYZE 线程>,确认是 MDL 排他锁。ANALYZE TABLE 在 8.0 里对 InnoDB 表拿的是 MDL 排他锁还是共享锁?自动重采样和手动 ANALYZE 是否一致?(如果能贴源码路径或官方文档更好)ANALYZE TABLE ... PERSISTENT 是否解决了这个问题?