一、优先方案:MySQL 8.0 Instant算法(秒级完成)
适用条件:
-
MySQL版本≥8.0.12
-
新增字段位于所有列的最后(不支持字段中间插入)
-
表非压缩格式(ROW_FORMAT≠COMPRESSED)
-
无全文索引/FTS表
操作命令:
-- 基础操作(默认使用INSTANT算法)
ALTER TABLE orders ADD COLUMN is_vip TINYINT DEFAULT 0 COMMENT 'VIP标识';
-- 显式指定算法(推荐)
ALTER TABLE orders
ADD COLUMN is_vip TINYINT DEFAULT 0 COMMENT 'VIP标识',
ALGORITHM=INSTANT;
优势:
-
执行时间0.1-0.6秒(亿级数据实测)
-
仅修改元数据(metadata),无需重建表
-
零数据复制,几乎无I/O压力
限制规避:
-
若需在字段中间添加列,可配合
AFTER
调整为末尾位置
ALTER TABLE orders
ADD COLUMN priority INT AFTER user_id, -- 尝试调整为末尾
ALGORITHM=INSTANT;
二、替代方案:在线DDL工具(适用于不满足Instant条件时)
pt-online-schema-change操作流程:
具体步骤:
pt-online-schema-change \
--user=dba_user \
--password=xxx \
--host=127.0.0.1 \
D=order_db,t=orders \
--alter "ADD COLUMN refund_amount DECIMAL(10,2) DEFAULT 0.00 COMMENT '退款金额'" \
--no-version-check \
--critical-load Threads_running=50 \
--chunk-size=2000 \
--max-lag=5 \
--execute
关键参数说明:
--chunk-size
每批迁移行数(建议2000-5000)
--max-lag
主从延迟阈值(秒),超时自动暂停
--critical-load
服务器负载阈值(如Threads_running>80暂停)
优势:
-
无锁表,写入业务不受影响
-
支持进度暂停/恢复,故障可回滚
三、传统方案:临时表重建(需停服或低峰期)
适用场景:
-
MySQL版本<8.0.12
-
新增字段需调整顺序
-
需同时修改多个字段属性
操作步骤:
-- 1. 创建临时表(含索引)
CREATE TABLE orders_new LIKE orders;
-- 2. 添加新字段(可任意调整位置)
ALTER TABLE orders_new
ADD COLUMN source_platform VARCHAR(20) DEFAULT 'web' COMMENT '来源平台';
-- 3. 分批导入数据(防止超时)
INSERT INTO orders_new (id, user_id, ..., source_platform)
SELECT id, user_id, ..., 'web' -- 显式赋值新字段
FROM orders
WHERE create_time < '2025-01-01'; -- 按时间分批
-- 4. 原子切换表(<1秒锁表)
RENAME TABLE orders TO orders_old, orders_new TO orders;
-- 5. 异步补增量数据(切换后的变更)
INSERT INTO orders (id, ... , source_platform)
SELECT o.id, ... , 'web'
FROM orders_old o
JOIN change_log c ON o.id = c.order_id; -- 记录变更日志
四、极端场景优化技巧
1.默认值选择
-
-
避免
NOT NULL
:建议允许NULL,业务层处理逻辑 -
大字段压缩:TEXT字段改用
COMPRESS()
函数存储
-
2.灰度发布策略
-- 步骤1:添加不可见字段(8.0.23+)
ALTER TABLE orders
ADD COLUMN experimental_flag INT INVISIBLE DEFAULT 0;
-- 步骤2:应用逐步适配后设为可见
ALTER TABLE orders
ALTER COLUMN experimental_flag SET VISIBLE;
3.亿级数据预分区
-- 按月分区减少单次操作量
ALTER TABLE orders PARTITION BY RANGE (YEAR(create_time)*100 + MONTH(create_time)) (
PARTITION p202501 VALUES LESS THAN (202502),
PARTITION p202502 VALUES LESS THAN (202503)
);
五、方案对比
方案 | 执行时间 | 锁表风险 | 适用场景 | 操作复杂度 |
---|---|---|---|---|
Instant算法 |
秒级 |
无 |
MySQL 8.0+,尾部加字段 |
⭐ |
pt-OSC工具 |
分钟~小时 |
无 |
任何版本,高频写入表 |
⭐⭐⭐ |
临时表重建 |
小时级 |
切换瞬间锁表 |
需修改字段顺序/属性 |
⭐⭐⭐⭐ |
分区表增量操作 |
天级 |
分区级锁定 |
超十亿级数据,可停机维护 |
⭐⭐⭐⭐ |
六、避坑关键点
- 空间检查
临时表方案需预留2倍磁盘空间
- 索引重建
新增字段若需加索引,建议分开执行(
ADD COLUMN
与ADD INDEX
分两步) - 默认值陷阱
-
避免全表更新:用
DEFAULT
替代UPDATE
语句 -
业务兼容:新字段写入需处理NULL值逻辑
-
- 主从延迟
工具执行时监控
Seconds_Behind_Master
,建议延迟<30秒
建议:先在从库验证(--dry-run
模式) ,生产环境选择业务低峰期(如02:00-05:00),并准备好回滚脚本(如FLASHBACK TABLE工具)。