gh-ost仅支持单表在线DDL,要求目标实例稳定、binlog_format=ROW且binlog_row_image=FULL、表有主键或NOT NULL唯一索引;必须执行--test-on-replica验证,cut-over前需确保连接充足、无长事务阻塞。

gh-ost 不是“迁移升级期间”的通用适配工具,它只负责单表在线 DDL 变更,和 MySQL 版本升级、实例迁移、主从切换等无关。如果你正处在 MySQL 升级或架构迁移过程中,想顺带改表结构,必须明确:gh-ost 本身不参与升级流程,它只在目标实例(主库或指定从库)上独立运行,且要求该实例状态稳定、binlog 可用、权限就绪。
binlog_format=ROW 和 binlog_row_image=FULL 缺一不可
gh-ost 依赖解析行级变更事件,不是靠猜测或触发器补全字段。漏掉任一条件都会在启动阶段直接报错退出,比如:
Cannot parse binlog event: only ROW format is supportedbinlog_row_image must be FULL
检查命令:
SHOW VARIABLES LIKE 'binlog_format';
SHOW VARIABLES LIKE 'binlog_row_image';
- 若
binlog_format是MIXED或STATEMENT:必须改,不能临时 SET(某些版本不支持动态改),推荐在my.cnf中写死并重启 - 若
binlog_row_image不是FULL:MySQL 5.6.22+ 才支持该变量,5.7+ 默认是FULL,但升级后若从旧配置继承了MINIMAL,gh-ost会漏掉被 UPDATE 的旧值,导致 ghost 表数据错乱
必须有主键或 NOT NULL 唯一索引
gh-ost 按主键/唯一键分块拷贝数据,没有它就无法确定扫描边界,会卡在初始化阶段:
- 报错示例:
Cannot find primary key or unique not null key on table - 允许复合唯一索引,但所有列都必须声明
NOT NULL -
UNIQUE (email)不行——如果email允许为NULL,哪怕只有一行是NULL,也不被接受 - 无主键表可先加:
ALTER TABLE t ADD COLUMN id BIGINT PRIMARY KEY AUTO_INCREMENT FIRST, ALGORITHM=INPLACE, LOCK=NONE;
注意:该语句本身是 Online DDL,但需确认当前无长事务阻塞 MDL 锁
--test-on-replica 不是可选项,是上线前必跑步骤
你不能跳过它直接在主库执行,否则可能因外键、字段类型隐式转换、字符集不一致等问题,在 cut-over 阶段失败,留下 _t_gho 和 _t_del 等残留表,还要人工清理。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 它会在从库完整走一遍流程:建
_t_gho、拷全量、追 binlog、checksum 校验,但不换表 - 成功后,务必手动比对:
SELECT COUNT(<em>) FROM t</em>vsSELECT COUNT() FROM _t_gho,再抽样查几条关键记录内容是否一致 - 若从库延迟大,
--test-on-replica会等它追平;若复制中断,gh-ost会报错退出,这反而是好事——说明环境不稳定,不该此时变更
cut-over 阶段失败常因连接数或锁竞争
最终换表不是简单 RENAME,而是靠两个连接协作加锁 + 哨兵表时间戳校验。常见失败现象:
Failed to acquire locks: timeoutConnection lost during cut-over
原因包括:
- 主库
max_connections不足,gh-ost至少需要 2 个空闲连接(一个用于LOCK TABLES,一个用于RENAME) - 网络抖动导致其中一个连接断开,整个 cut-over 回滚,ghost 表保留,原表不变
- 原表上有未提交的长事务,持有 MDL 读锁,阻塞
LOCK TABLES请求
建议操作前检查:SHOW PROCESSLIST 中是否有运行超 30 秒的 SELECT 或未提交事务;临时调高 max_connections 并预留冗余连接。
真正的难点不在命令怎么写,而在于你能否准确判断当前主从拓扑、binlog 状态、权限覆盖、以及表结构约束是否全部满足——缺一环,gh-ost 就不会动。

















