结构变更(DDL)需遵循避免锁表、规避长事务、保障可回退、全程可观测原则;操作前须查结构、评估数据量、检查活跃会话;小表可直接改,大表必须用在线工具。

结构变更(DDL)是数据库运维中最容易引发故障的操作之一,关键不在于“能不能改”,而在于“怎么改才不伤数据、不卡服务、不丢一致性”。核心原则是:避免锁表、规避长事务、保障可回退、全程可观测。
先查再改:确认影响范围
任何 DDL 前必须明确它对当前表的实际影响:
- 用 SHOW CREATE TABLE 表名 查看现有结构、引擎、字符集、索引,避免隐式转换或默认值冲突
- 用 SELECT COUNT(*) FROM 表名 和 SELECT DATA_LENGTH, INDEX_LENGTH FROM information_schema.TABLES 评估表大小,大表(千万行以上 / GB 级)需走在线变更方案
- 用 SELECT * FROM information_schema.PROCESSLIST WHERE COMMAND != 'Sleep' 检查活跃会话,避开高峰期和长查询窗口
小表直接改,大表用在线工具
MySQL 5.6+ 的 ALGORITHM=INPLACE 并非万能——它只对部分操作免锁(如加普通索引),但加主键、改列类型、删列等仍可能触发重建表。别轻信“online DDL”宣传语:
- 小表(ALTER TABLE ... ADD COLUMN ... DEFAULT ...,但记得显式指定 AFTER 列名 控制位置,避免字段顺序混乱
- 中大表(100 万行起):优先用 pt-online-schema-change(Percona Toolkit)或 gh-ost,它们通过影子表+binlog 拆分写入,全程无锁,支持暂停/取消/限速
- 禁止在从库执行 DDL:主从延迟下可能导致复制中断;所有变更统一在主库发起,让从库自动同步
变更过程必须可控、可验、可退
一次安全的结构变更不是单条 SQL,而是一组带检查点的操作链:
- 提前备份元数据:运行 mysqldump -d -t -n 数据库名 表名 > before.sql 记录原始结构(-d 不导数据,-t 不导建表语句,-n 不加 USE)
- 加字段必设默认值且非 NULL:否则 MySQL 5.7+ 会为历史行填充 NULL,后续应用读取易出错;若业务允许空值,显式写 DEFAULT NULL
- 变更后立即验证:查 DESCRIBE 表名 确认字段存在、类型正确;跑 SELECT * FROM 表名 LIMIT 1 看是否报错;插入一条测试数据验证写入逻辑
- 保留回滚脚本:比如加了字段,回滚脚本就是 ALTER TABLE 表名 DROP COLUMN 字段名;提前在测试库验证该语句是否真的能快速执行
上线后盯住三件事
DDL 执行完不等于结束,接下来 15–30 分钟是风险高发期:
- 监控 Threads_running 和 Innodb_row_lock_waits 是否突增——说明有锁竞争残留
- 检查慢查询日志,确认新增字段未导致索引失效(例如 WHERE 新字段 = ? 却没建索引)
- 观察应用日志,重点看 ORM 层是否因字段名大小写、类型映射变化报错(如 tinyint(1) 被当成布尔,升级后变成 int)










