MySQL执行DDL时阻塞DML是MDL锁机制强制行为:DDL需独占写锁,而未提交的DML/DQL持有共享读锁,二者互斥;常见阻塞源为长事务、慢查询或未提交SELECT,可通过performance_schema.metadata_locks与INNODB_TRX联合定位。

MySQL执行DDL时阻塞所有DML,根本不是“性能差”或“配置没调好”,而是MDL(Metadata Lock)机制的强制行为——DDL必须获取独占元数据锁,而任何未提交的DML(哪怕只是SELECT)都持有共享MDL锁,二者互斥。
DDL卡在Waiting for table metadata lock时怎么定位源头
这不是DDL慢,是它被别的事务按住了。最常见的是长事务、未提交的SELECT、或慢查询占着连接不放。
- 查持锁会话:
SELECT * FROM performance_schema.threads WHERE PROCESSLIST_STATE = 'Sleep' AND PROCESSLIST_INFO IS NULL;,再结合performance_schema.metadata_locks关联查谁拿了S锁没释放 - 快速确认活跃事务:
SELECT * FROM information_schema.INNODB_TRX ORDER BY TRX_STARTED LIMIT 5;,重点看TRX_STATE = 'RUNNING'且TRX_STARTED时间异常早的 - 别信
SHOW PROCESSLIST里状态为Sleep的连接——它可能正拿着MDL共享锁,KILL前务必用performance_schema交叉验证
ALTER TABLE ... ALGORITHM=INPLACE, LOCK=NONE为什么还是阻塞
INPLACE ≠ 无锁,LOCK=NONE ≠ 绝对不阻塞。这个组合只对特定操作生效,且依赖存储引擎和字段变更类型。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 修改列类型(如
INT→BIGINT)在MySQL 5.7中仍需REBUILD,即使ALGORITHM=INPLACE,也会在应用增量阶段短暂加XMDL锁 -
LOCK=NONE仅在“仅改元数据”类操作中真正生效,比如ADD COLUMN(8.0.12+ INSTANT)、DROP INDEX;但MODIFY COLUMN或CHANGE COLUMN基本都会退化为LOCK=SHARED或更严 - 用
INFORMATION_SCHEMA.INNODB_METRICS查dml_rows_inserted等指标突降,能佐证是否真有DML被卡住,而非应用层超时假象
从库上执行DDL导致SQL线程停摆怎么办
从库SQL线程单线程串行重放,遇到DDL就全程占用,后续所有表的DML都排队——这不是延迟,是复制链路“断流”。
- 别指望
slave_parallel_type=database能救DDL:它只分发DML,DDL自带全库级MDL锁升级,所有worker都会被路由到同一个线程 -
slave_parallel_type=logical_clock也仅缓解:它依赖主库开启binlog_transaction_dependency_tracking=WRITESET,而DDL本身不产生writeset,前后事务的时间戳切片对它无效 - 实操更可靠的做法是“绕过复制”:
STOP SLAVE SQL_THREAD;→ 在从库手动执行DDL(前提:已用pt-table-checksum校验主从一致性)→START SLAVE SQL_THREAD;
真正容易被忽略的点是:DDL阻塞DML的临界点不在DDL开始那一刻,而在它尝试升级MDL锁的瞬间——此时只要有一个未提交的SELECT在跑,哪怕只查一行,整个表的写入就停了。监控不能只盯Seconds_Behind_Master,得实时抓metadata_locks和INNODB_TRX联动视图。










