借助gh-ost,对MySQL大表进行表结构的变更

关于 gh-ost

gh-ost 是 GitHub 开发的一个 MySQL 在线表结构变更工具(online schema migration tool)。它的全称是 "GitHub's Online Schema Translator"。

gh-ost 现在已经是大型互联网公司进行数据库运维的重要工具。

主要作用

gh-ost 允许在不锁表、不影响业务的情况下,对 MySQL 数据库表进行结构变更(如添加列、修改索引等)。

核心特点

  1. 无触发器设计 - 不像传统工具使用触发器来同步数据,gh-ost 通过解析 binlog 来捕获变更
  2. 可暂停/恢复 - 可以随时暂停迁移过程,对生产环境更友好
  3. 可测试 - 支持在从库上测试变更,确认无误后再应用到主库
  4. 动态调整 - 可以实时调整迁移速度,避免影响线上服务

工作原理

  1. 创建一个与原表结构相同的"影子表"(ghost table)
  2. 在影子表上执行 DDL 变更
  3. 通过 binlog 将原表的增量数据同步到影子表
  4. 数据同步完成后,快速切换表名完成迁移

使用方法

  1. 安装
    gh-ost 可以直接从最新的 发布页面 下载二进制文件,支持 Linux 和 macOS。

  2. 基本命令

    • 测试迁移

      bash 复制代码
      gh-ost --test-on-replica --database=mydb --table=mytable --alter="ADD COLUMN new_col INT" --execute
    • 真实迁移

      bash 复制代码
      gh-ost --database=mydb --table=mytable --alter="ADD COLUMN new_col INT" --execute

实际例子

假设你有一个用户表需要添加新字段:

bash 复制代码
gh-ost \
  --host=localhost \
  --user=root \
  --password=password \
  --database=mydb \
  --table=users \
  --alter="ADD COLUMN age INT DEFAULT 0" \
  --execute

场景说明:

  • 原表 users 有 1000 万条数据
  • 使用传统 ALTER TABLE 可能需要锁表数小时
  • 使用 gh-ost 可以在后台逐步完成变更,期间用户可以正常读写数据
  • 最后只需要几秒钟的短暂切换时间即可完成迁移

适用场景

  • 大表的结构变更(百万级以上数据)
  • 需要保证高可用性的生产环境
  • 需要精确控制数据库负载的情况

数据库支持范围

gh-ost 目前只适用于 MySQL(包括 Percona Server 和 MariaDB)。它依赖 MySQL 的 binlog 机制,因此不支持 PostgreSQL、Oracle 等其他数据库。

常见的坑

1. 外键约束问题

gh-ost 不支持有外键的表。如果表有外键关系,迁移会失败。

复制代码
解决办法: 需要先删除外键,迁移完成后再重新添加

2. binlog 格式要求

必须使用 ROW 格式的 binlog,STATEMENT 或 MIXED 格式不支持。

sql 复制代码
-- 检查 binlog 格式
SHOW VARIABLES LIKE 'binlog_format';

-- 如果不是 ROW,需要修改配置
SET GLOBAL binlog_format = 'ROW';

3. 主键要求

必须有主键或唯一索引,否则 gh-ost 无法正常工作。

4. 磁盘空间

会创建影子表,需要额外的磁盘空间(大约是原表的大小)。如果磁盘空间不足,迁移会失败。

5. 复制延迟

如果主从复制本身就有延迟,gh-ost 的迁移会进一步加重延迟。需要监控 --max-lag-millis 参数。

6. 触发器冲突

虽然 gh-ost 本身不用触发器,但如果原表上已有触发器,可能会导致数据不一致。

7. 字符集问题

影子表的字符集需要与原表一致,否则可能出现乱码或数据截断。

8. 长时间迁移中断

如果迁移过程很长(几天),期间 MySQL 重启或 binlog 被清理,会导致迁移失败需要重新开始。

实践建议

bash 复制代码
# 先在从库测试
gh-ost \
  --host=slave-host \
  --test-on-replica \
  --migrate-on-replica \
  --database=mydb \
  --table=users \
  --alter="ADD COLUMN age INT" \
  --execute

# 设置合理的限流参数
gh-ost \
  --max-load=Threads_running=25 \
  --critical-load=Threads_running=100 \
  --chunk-size=1000 \
  --throttle-query="SELECT HOUR(NOW()) BETWEEN 2 AND 6" \
  --execute

替代方案

如果 gh-ost 不适用,可以考虑:

  • pt-online-schema-change (Percona Toolkit)
  • 原生 Online DDL (MySQL 5.6+ 支持部分操作)
  • 对于其他数据库,PostgreSQL 可以用 pg_repack
相关推荐
Lethehong2 小时前
破局Oracle迁移困局:破局Oracle迁移困局:直面兼容性与成本的隐性痛点
数据库·oracle
amazing-yuan2 小时前
Windows系统查看是否已安装Mysql,查找Mysql的安装地址,忘记root账号的密码时重置密码操作指引
数据库·windows·mysql
WangYaolove13142 小时前
基于人脸表情的分类算法的设计(源码+文档)
python·mysql·django·毕业设计·源码
枫叶丹42 小时前
Oracle迁移实战:破解兼容性难题与高成本挑战
开发语言·数据库·oracle
济6172 小时前
linux 系统移植(第十期)----Linux 顶层 Makefile详谈-- Ubuntu20.04
linux·服务器·数据库
踢足球09292 小时前
寒假打卡:2026-01-21
数据库·sql
驾驭人生2 小时前
Nacos 2.2.3 生产级部署指南(单机 + MySQL + 鉴权)
数据库·mysql
茁壮成长的露露2 小时前
pbm物理备份恢复
数据库·mongodb
星梦清河2 小时前
MySQL--常见函数
数据库·mysql