他的回复:
一、Online DDL 的核心原理MySQL 5.6 起支持 Online DDL,本质是把「重建整张表」拆成三个阶段,尽量减少对 DML 的阻塞:1)Prepare 阶段:短暂获取 MDL 共享锁(通常毫秒级),校验表结构、决定执行算法(COPY / INPLACE / INSTANT),并准备临时日志。2)Execute 阶段:持有 MDL 共享锁但不阻塞 DML,DDL 在后台执行(如构建索引、重建表),期间并发产生的增删改会记录到 online log(row log)中。3)Commit 阶段:消耗 online log、重放增量变更,最后升级为 MDL 排他锁做元数据切换。此阶段极短,但若 online log 过大也会明显变长。关键点:Online DDL 并不等于「完全不锁表」,prepare 和 commit 阶段仍需要 MDL 锁,所以长事务、未提交事务会阻塞 DDL,进而阻塞后续所有请求(经典的 MDL 等待雪崩)。二、可以做到不锁表(LOCK=NONE)的常见 ALTER 操作• 索引类:ADD INDEX / ADD UNIQUE INDEX / DROP INDEX / RENAME INDEX,均为 INPLACE 算法,支持 LOCK=NONE;• 加列:MySQL 8.0.12+ 支持 INSTANT ADD COLUMN(仅改数据字典,秒级完成);5.7 为 INPLACE,需要重建表但支持并发 DML;• 删列:8.0.29+ 支持 INSTANT DROP COLUMN;更早版本为 INPLACE;• 修改列默认值、自增起始值、表注释、列注释:INSTANT,仅改元数据;• 重命名列(8.0 RENAME COLUMN):INPLACE,仅改元数据;• 修改列的可空性(NULL ↔ NOT NULL):INPLACE,但需要重建表;• 扩展 VARCHAR 长度(在 0~255 与 256+ 的边界内不变时):INPLACE;• 添加/删除外键(需 foreign_key_checks=0):INPLACE,支持 LOCK=NONE。三、仍然会锁表或必须 COPY 重建的操作• 修改列类型(如 INT→BIGINT 部分场景可 INPLACE,VARCHAR 缩短、DECIMAL 精度变更通常需要 COPY);• 修改表级字符集/排序规则(CONVERT TO CHARACTER SET):COPY,全程锁写;• 新增主键、修改主键列:多数场景 COPY;• 添加 FULLTEXT 索引:INPLACE 但需重建全文索引,期间写入性能明显下降;• 修改存储引擎、表分区规则、行格式:通常 COPY。四、实践建议1)显式声明 ALGORITHM=INPLACE, LOCK=NONE,让 MySQL 在无法满足时直接报错而不是悄悄降级锁表,例如:ALTER TABLE t ADD INDEX idx_c1 (c1), ALGORITHM=INPLACE, LOCK=NONE;2)DDL 前检查长事务:SELECT * FROM information_schema.innodb_trx ORDER BY trx_started LIMIT 10; 避免 MDL 等待拖垮业务;3)关注 innodb_online_alter_log_max_size(默认 128M),大表高并发写入时 online log 溢出会导致 DDL 失败回滚;4)超大表建议用 gh-ost 或 pt-online-schema-change,配合限流与主从切换,可控性更好;5)在主从架构中评估复制延迟:大表 DDL 在主库执行完后,从库回放可能持续很久,建议先在从库或影子表验证。