MySQL亿级大表安全添加字段的三种方案!
MySQL亿级大表安全添加字段的三种方案!
作者:码农阿豪@新空间
面对 1.35亿条数据 的 MySQL 表添加字段,传统 ALTER TABLE 可能导致长时间锁表,严重影响业务,本文将提供一套完整的 零停机方案,涵盖 Online DDL 优化、专业工具使用 和 Java 应用层配合策略,需要的朋友可以参考下。
1. 亿级大表 ALTER 的风险评估
1.1 直接执行 ALTER 的潜在问题
1
|
ALTER TABLE `orders` ADD COLUMN `is_priority` TINYINT NULL DEFAULT 0; |
- 锁表时间估算(经验值):
- MySQL 5.6:约 2-6小时(完全阻塞)
- MySQL 5.7+:10-30分钟(短暂阻塞写入)
- 业务影响:
- 所有读写请求超时
- 连接池耗尽(
Too many connections
) - 可能触发高可用切换(如 MHA)
1.2 关键指标检查
1
2
3
4
5
6
7
8
9
10
|
-- 查看表大小(GB) SELECT table_name, ROUND(data_length/1024/1024/1024,2) AS size_gb FROM information_schema.tables WHERE table_schema = 'your_db' AND table_name = 'orders' ; -- 检查当前长事务 SELECT * FROM information_schema.innodb_trx WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60; |
2. 三种安全方案对比
方案 | 工具 | 执行时间 | 阻塞情况 | 适用版本 | 复杂度 |
---|---|---|---|---|---|
Online DDL | 原生MySQL | 30min-2h | 短暂阻塞写 | 5.7+ | ★★☆ |
pt-osc | Percona Toolkit | 2-4h | 零阻塞 | 所有版本 | ★★★ |
gh-ost | GitHub | 1-3h | 零阻塞 | 所有版本 | ★★★★ |
3. 方案一:MySQL 原生 Online DDL(5.7+)
3.1 最优执行命令
1
2
3
4
|
ALTER TABLE `orders` ADD COLUMN `is_priority` TINYINT NULL DEFAULT 0, ALGORITHM=INPLACE, LOCK=NONE; |
3.2 监控进度(另开会话)
1
2
3
4
5
|
-- 查看 DDL 状态 SHOW PROCESSLIST; -- 查看 InnoDB 操作进度 SELECT * FROM information_schema.innodb_alter_table; |
3.3 预估执行时间(经验公式)
1
|
时间( min ) = 表大小(GB) × 2 + 10 |
- 假设表大小 50GB → 约 110分钟
4. 方案二:pt-online-schema-change 实战
4.1 安装与执行
1
2
3
4
5
6
7
8
9
10
11
|
# 安装 Percona Toolkit sudo yum install percona-toolkit # 执行变更(自动创建触发器) pt-online-schema-change \ --alter "ADD COLUMN is_priority TINYINT NULL DEFAULT 0" \ D=your_db,t=orders \ --chunk-size=1000 \ --max-load= "Threads_running=50" \ --critical-load= "Threads_running=100" \ --execute |
4.2 关键参数说明
参数 | 作用 | 推荐值(亿级表) |
---|---|---|
--chunk-size |
每次复制的行数 | 500-2000 |
--max-load |
自动暂停阈值 | Threads_running=50 |
--critical-load |
强制中止阈值 | Threads_running=100 |
--sleep |
批次间隔时间 | 0.5(秒) |
4.3 Java 应用兼容性处理
1
2
3
4
5
6
7
|
// 在触发器生效期间,需处理重复主键异常 try { orderDao.insert(newOrder); } catch (DuplicateKeyException e) { // 自动重试或走降级逻辑 orderDao.update(newOrder); } |
5. 方案三:gh-ost 高级用法
5.1 执行命令(无需触发器)
1
2
3
4
5
6
7
8
|
gh-ost \ --database= "your_db" \ --table= "orders" \ --alter= "ADD COLUMN is_priority TINYINT NULL DEFAULT 0" \ --assume-rbr \ --allow-on-master \ -- cut -over=default \ --execute |
5.2 核心优势
- 无触发器设计:避免性能损耗
- 动态限流:自动适应服务器负载
- 可交互控制:支持暂停/恢复
1
2
3
|
# 运行时控制 echo throttle | nc -U /tmp/gh-ost .sock echo no-throttle | nc -U /tmp/gh-ost .sock |
6. Java 应用层适配策略
6.1 双写兼容模式(推荐)
1
2
3
4
5
6
7
8
9
10
|
// 在变更期间同时写入新旧字段 public void createOrder(Order order) { order.setIsPriority( 0 ); // 新字段默认值 orderMapper.insert(order); // 兼容旧代码 if (order.getV2() == null ) { orderMapper.updateIsPriority(order.getId(), 0 ); } } |
6.2 动态 SQL 路由
1
2
3
4
5
6
7
8
9
|
<!-- MyBatis 动态字段映射 --> < insert id = "insertOrder" > INSERT INTO orders (id, user_id, amount < if test = "isPriority != null" >, is_priority</ if >) VALUES (#{id}, #{userId}, #{amount} < if test = "isPriority != null" >, #{isPriority}</ if >) </ insert > |
7. 监控与回滚方案
7.1 实时监控指标
1
2
3
4
5
|
# 监控复制延迟(主从架构) pt-heartbeat --monitor --database=your_db # 查看 gh-ost 进度 tail -f gh-ost.log |
7.2 紧急回滚步骤
1
2
3
4
5
|
# pt-osc 回滚(自动清理临时表) pt-online-schema-change --drop-new-table --alter= "..." --execute # gh-ost 回滚 gh-ost --panic-on-failure --revert |
8. 总结建议
- 首选方案:
- MySQL 8.0 → 原生
ALGORITHM=INSTANT
(秒级完成) - MySQL 5.7 →
gh-ost
(无触发器影响)
- MySQL 8.0 → 原生
- 执行窗口:
- 选择业务流量最低时段(如凌晨 2-4 点)
- 提前通知业务方准备降级方案
- 验证流程:
1
2
|
-- 变更后检查数据一致性 SELECT COUNT (*) FROM orders WHERE is_priority IS NULL ; |
- 后续优化:
1
2
3
|
-- 添加完成后可改为 NOT NULL ALTER TABLE orders MODIFY COLUMN is_priority TINYINT NOT NULL DEFAULT 0; |
通过合理选择工具+应用层适配,即使 1.35亿条数据 的表也能实现 零感知 的字段添加。
以上就是MySQL亿级大表安全添加字段的三种方案的详细内容。
学习资料见知识星球。
以上就是今天要分享的技巧,你学会了吗?若有什么问题,欢迎在下方留言。
快来试试吧,小琥 my21ke007。获取 1000个免费 Excel模板福利!
更多技巧, www.excelbook.cn
欢迎 加入 零售创新 知识星球,知识星球主要以数据分析、报告分享、数据工具讨论为主;
1、价值上万元的专业的PPT报告模板。
2、专业案例分析和解读笔记。
3、实用的Excel、Word、PPT技巧。
4、VIP讨论群,共享资源。
5、优惠的会员商品。
6、一次付费只需129元,即可下载本站文章涉及的文件和软件。