一、视频主题
这个视频主要讲的是一个 Java 后端面试高频场景:
面试官问:千万级订单表要新增字段,你敢直接执行
ALTER TABLE吗?
示例 SQL:
ALTER TABLE orders
ADD COLUMN source_channel VARCHAR(32) NOT NULL DEFAULT 'APP';
视频核心不是普通查询 SQL 调优,而是围绕 **大表 DDL 变更、在线改表、架构兜底设计、面试回答方式** 展开。
二、业务背景
视频假设的场景是:
电商系统
orders 表有 2000 万数据
现在需要给 orders 表新增字段 source_channel
字段类型:VARCHAR(32)
非空
默认值:APP
面试官追问:
能不能直接在线上执行 ALTER?
会不会锁表?
有没有更稳妥的方案?
如果历史数据要回填怎么办?
三、方案一:直接 ALTER —— 高风险方案
1. 直接执行
ALTER TABLE orders
ADD COLUMN source_channel VARCHAR(32) NOT NULL DEFAULT 'APP';
2. 风险点
视频指出,大表直接 ALTER 风险很高,尤其是 MySQL 低版本或复杂 DDL 场景。
可能出现的问题:
1. 锁表
2. 业务写入阻塞
3. DDL 执行时间长
4. 磁盘 IO 飙升
5. 主从延迟
6. 线上查询/写入超时
7. 影响核心订单链路
3. MySQL 版本差异
视频里提到:
MySQL 5.5 之前:DDL 很容易锁全表
MySQL 5.6+:支持 Online DDL,但不是完全无风险
即使是 Online DDL,也可能在最后提交阶段产生短暂锁等待。
四、方案二:Online DDL —— 及格答案
MySQL 5.6+ 支持 Online DDL,执行过程大致分为:
初始化
↓
执行阶段
↓
提交阶段
1. 执行阶段
Online DDL 大部分时间不锁表,业务读写可以继续进行。
但是 DDL 过程中会记录增量变更日志。
相关参数:
innodb_online_alter_log_max_size
如果这个参数设置太小,在高并发写入场景下可能出现问题。
2. 风险点
Online DDL 不是完全无锁。
可能风险:
1. 最后提交阶段仍然可能等待 MDL 锁
2. 高并发场景下可能因为长事务导致 DDL 卡住
3. 大表 DDL 会造成 IO 压力
4. 可能引起主从延迟
5. 如果有慢查询或长事务,DDL 可能一直等待
3. 面试中不能只说 Online DDL
只回答:
用 Online DDL 就行
是不够的。
更好的回答应该补充:
1. 先看 MySQL 版本
2. 看字段变更类型
3. 看是否会重建表
4. 看当前业务高峰期和低峰期
5. 看是否存在长事务
6. 看主从延迟和磁盘空间
7. 准备回滚方案
五、方案三:pt-osc / gh-ost —— 高分方案
视频提到两类在线改表工具:
pt-online-schema-change,简称 pt-osc
gh-ost
1. pt-osc 思路
pt-osc 的核心思路是:
1. 创建影子表
2. 在影子表上执行表结构变更
3. 通过触发器同步源表增量数据
4. 拷贝历史数据到影子表
5. 最后 rename 切换表
缺点:
1. 需要触发器
2. 对数据库有额外压力
3. 最后 rename 阶段仍然可能有短暂锁
4. 老项目中使用较多
2. gh-ost 思路
gh-ost 的核心思路是:
1. 创建 ghost 表
2. 读取 binlog 同步增量数据
3. 拷贝历史数据
4. 最后切换表
优点:
1. 不依赖触发器
2. 通过 binlog 同步增量
3. 对业务表侵入更小
4. 可暂停、可限速、可观察
5. 更适合现代 MySQL 架构
3. gh-ost 示例命令
视频里展示了类似命令:
gh-ost \
--database=mall \
--table=orders \
--alter="ADD COLUMN source_channel VARCHAR(32)" \
--execute
实际生产中还需要补充:
1. 主库/从库连接配置
2. cut-over 策略
3. 限速参数
4. 延迟监控
5. chunk-size
6. max-load
7. critical-load
8. panic flag file
六、方案四:新建扩展表 —— 架构师思维
视频提出一个更偏架构设计的方案:不一定非要改原订单主表,可以新建订单扩展表。
示例:
CREATE TABLE order_ext (
order_id BIGINT PRIMARY KEY,
source_channel VARCHAR(32) NOT NULL DEFAULT 'APP'
);
1. 优点
1. 不改核心订单主表结构
2. 避免对大表直接 DDL
3. 降低核心链路风险
4. 扩展字段可以独立维护
5. 适合非核心字段、营销字段、渠道字段
2. 缺点
1. 查询订单详情时可能需要 JOIN
2. 高 QPS 场景下 JOIN 有性能成本
3. 需要考虑缓存或冗余
4. 需要保证扩展表数据一致性
3. 适合场景
适合这类字段:
渠道字段
营销字段
标签字段
非核心业务字段
变化频繁的扩展属性
不适合所有字段都放扩展表,否则查询复杂度会升高。
七、方案五:预留冗余字段 —— 防御性设计
视频提到可以提前预留一些扩展字段,例如:
ext_1
ext_2
ext_3
extra_json
1. 好处
1. 后续小需求不用频繁改表
2. 避免大表 DDL 风险
3. 对临时业务字段更友好
2. 风险
视频也强调,这种设计不能乱用。
常见问题:
1. 语义黑盒:ext_1 今天存渠道,明天可能又存活动 ID
2. 类型混乱:VARCHAR 里存数字、日期、JSON
3. 索引困难:想搜索时不好建索引
4. 维护困难:新人不知道 ext_3 代表什么
5. 容易变成垃圾字段
3. 正确使用方式
如果使用预留字段,必须配套:
1. 字段语义注册表
2. Wiki 文档
3. 字段使用约束
4. 字段负责人
5. 字段生命周期管理
6. 不允许随意复用
八、方案六:PostgreSQL 的降维打击
视频中还提到 PostgreSQL 在某些 DDL 场景下比 MySQL 更友好。
大意是:
PostgreSQL 11+ 对 ADD COLUMN DEFAULT 做了优化
某些加字段默认值操作不需要重写整张表
而 MySQL 面试中更多关注:
1. 怎么安全地改大表
2. 是否锁表
3. 是否产生主从延迟
4. 是否影响线上业务
5. 是否有回滚方案
这部分的核心意思是:
不同数据库对 DDL 的实现不同,不能把 MySQL 的经验直接套到 PostgreSQL 上。
九、视频给出的面试满分回答模板
视频最后总结了一个高分回答思路:
首先,我不会直接 ALTER。
我会先评估字段属性:
如果是核心高频查询字段,优先用 gh-ost 在线改表,低峰期执行,开启限速和监控。
如果是扩展属性,我会考虑新建扩展表,或者复用预留字段,避免动核心表结构。
同时准备回滚预案,确保磁盘空间和主从延迟可控。
这个回答体现了:
1. 风险意识
2. 工具熟练度
3. 架构前瞻性
4. 线上生产经验
5. 不盲目直接改表
十、面试官可能继续追问
视频结尾抛出了一个追问:
改完字段后,历史 2000 万条数据的 source_channel 怎么回填?
这个问题不能直接说:
UPDATE orders SET source_channel = 'APP';
因为一次性更新 2000 万数据会有很大风险。
十一、历史数据回填的推荐方案
1. 分批回填
推荐按主键范围分批更新:
UPDATE orders
SET source_channel = 'APP'
WHERE id > 0
AND id <= 10000
AND source_channel IS NULL;
然后循环推进:
1 ~ 10000
10001 ~ 20000
20001 ~ 30000
...
2. 控制每批大小
建议:
每批 1000 ~ 10000 条
根据数据库压力动态调整。
3. 避免大事务
不要一次提交 2000 万条。
应该:
每批一个事务
更新后提交
短暂 sleep
继续下一批
4. 增加回填进度表
可以设计一张任务表:
CREATE TABLE data_backfill_task (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
table_name VARCHAR(64),
field_name VARCHAR(64),
last_id BIGINT,
status VARCHAR(32),
create_time DATETIME,
update_time DATETIME
);
用于记录:
1. 当前回填到哪个 ID
2. 是否执行成功
3. 是否可以断点续跑
4. 失败后从哪里恢复
5. 低峰执行
建议在:
凌晨
业务低峰期
数据库压力低的时候
执行回填任务。
6. 监控指标
回填时必须监控:
1. CPU
2. 磁盘 IO
3. 慢 SQL
4. 主从延迟
5. 锁等待
6. QPS
7. 业务接口耗时
十二、完整面试回答示例
如果面试官问:
千万级订单表加字段,你敢直接 ALTER 吗?
可以这样回答:
我不会直接在线上执行 ALTER,尤其是 orders 这种核心大表。
我会先判断 MySQL 版本、字段类型、是否带默认值、是否 NOT NULL、是否会触发表重建,以及当前表的数据量、QPS、主从延迟和磁盘空间。
如果这个字段是核心查询字段,必须放在 orders 表里,我会优先使用 gh-ost 或 pt-osc 做在线变更,在业务低峰期执行,并配置限速、主从延迟监控、cut-over 策略和回滚方案。
如果这个字段只是扩展属性,比如渠道、营销、标签类字段,我会优先考虑新建 order_ext 扩展表,避免直接修改核心订单主表。
如果公司已有规范,也可以使用预留字段,但必须有字段语义注册表和 Wiki 约束,避免 ext 字段语义混乱。
对于历史数据回填,我不会一次性 UPDATE 全表,而是按主键范围分批回填,每批几千条,记录回填进度,支持失败重试和断点续跑,同时监控主从延迟、锁等待和业务接口耗时。
十三、视频核心结论
千万级订单表加字段,不能只会说直接 ALTER。
真正的高分答案应该包括:
1. 不直接裸 ALTER
2. 先评估字段属性和业务影响
3. MySQL 5.6+ 可以考虑 Online DDL,但仍有锁等待风险
4. 大表核心字段优先使用 gh-ost / pt-osc
5. 非核心扩展字段可以考虑扩展表
6. 临时扩展可以考虑预留字段,但必须有字段语义管理
7. 历史数据回填必须分批、限速、可恢复
8. 全过程要监控主从延迟、锁等待、磁盘和业务接口耗时
十四、一句话总结
这个视频讲的是:面对千万级订单表新增字段,不能简单直接 ALTER,而要根据字段重要性、数据库版本、业务压力和风险等级,选择 Online DDL、gh-ost/pt-osc、扩展表或预留字段,并配合低峰执行、限速、监控、回滚和分批回填。