mysql 5.7+ 能用 algorithm=inplace, lock=none 就别硬扛,但超千万行、有主从延迟或高写入压力时必须用 gh-ost 或 pt-online-schema-change;8.0+ 新增字段优先走 instant 算法。

ALGORITHM=INPLACE, LOCK=NONE 就别硬扛,但超过千万行、有主从延迟或写入压力大的表,必须用 gh-ost 或 pt-online-schema-change;8.0+ 新增字段优先走 INSTANT,它真不锁表。
什么时候该放弃原生 ALTER TABLE?
不是所有“在线 DDL”都真的能扛住生产压力。MySQL 原生 ALTER TABLE 在以下情况会退化为 COPY 算法,导致锁表或长时间阻塞:
- 修改列类型(如
VARCHAR(50)→VARCHAR(255)),即使指定了ALGORITHM=INPLACE,也可能被降级 - 在非末尾位置添加字段(用了
FIRST或AFTER),触发全表重建 - 表无主键或唯一索引,
LOCK=NONE直接失效 -
innodb_online_alter_log_max_size太小,DML 日志溢出后自动暂停甚至失败
典型错误现象:Waiting for table metadata lock 卡住数分钟,或 SHOW PROCESSLIST 中看到 altering table 状态持续不退。
pt-online-schema-change 卡住的常见原因和应对
pt-online-schema-change 不是慢,是主动保护——它靠触发器捕获变更,一旦感知到风险就暂停拷贝。卡住日志里常出现:
-
Waiting for the slave to catch up:说明主从延迟超--max-lag阈值,需先压降从库延迟 -
Pausing due to high load:--max-load(如Threads_running=50)被突破,检查当前SHOW GLOBAL STATUS LIKE 'Threads_running' -
ERROR 1442 (HY000): Can't update table in stored function/trigger:源表已有触发器,工具拒绝执行,必须先清理或换gh-ost - 外键报错
Foreign key constraints are not supported:必须加--alter-foreign-keys-method=auto
关键限制必须提前确认:pt-online-schema-change 要求源表有主键或唯一索引,且磁盘空间预留 ≥ 2 倍表大小(原表 + 影子表 + binlog 日志)。
gh-ost 为什么更适合高负载或托管 RDS 环境?
gh-ost 绕过了触发器,直接解析 binlog,天然规避了 pt-osc 的核心瓶颈。但它对环境有硬性依赖:
-
binlog_format必须为ROW,否则无法还原变更 -
binlog_row_image必须为FULL(MySQL 5.6+ 默认满足) - 账号需有
REPLICATION SLAVE和REPLICATION CLIENT权限 - 不支持修改主键列、分区表、或含
ENUM/SET的列(部分版本已实验支持,但上线前务必实测)
典型命令:gh-ost --host=xxx --database=test --table=t_user --alter="ADD COLUMN c4 VARCHAR(32)" --allow-on-master --execute。注意 --allow-on-master 是必须显式加的,RDS 类服务默认禁用从库连接,只能直连主库。
DDL 变更前最容易被忽略的三件事
很多人只盯着工具参数调优,却漏掉真正影响成败的基础项:
- 没确认
autocommit=1:工具内部事务依赖自动提交,关了会导致死锁或超时 - 没备份
information_schema.TABLES中的表大小和索引信息:变更失败回滚时,靠它快速判断是否残留影子表或触发器 - 没验证应用层兼容性:比如新增
NOT NULL字段但没设默认值,INSERT 语句会直接报错,而工具日志里不会体现
尤其注意:gh-ost 切换阶段(cut-over)仍是原子 rename,虽快(毫秒级),但会短暂阻塞新 DML —— 这个窗口没法消除,只能靠业务侧配合避开峰值。











