必须先验证全部前提条件,否则algorithm=inplace, lock=none会报错或退化为lock=shared导致写入阻塞;需确认引擎为innodb、binlog_format=row、无外键、无全文/空间索引、innodb_file_per_table=on、text/blob列已指定前缀,且联合索引字段顺序须按等值查询优先、高区分度列居左、范围查询列置右。

ALTER TABLE ... ALGORITHM=INPLACE, LOCK=NONE 能否直接用?
不能默认就用,必须先验证表是否满足全部前提条件——MySQL 不会静默降级,而是直接报错或退化为 LOCK=SHARED,导致写入阻塞。
检查清单:
- 引擎必须是
InnoDB(SHOW CREATE TABLE t看ENGINE=InnoDB) -
binlog_format必须为ROW(SELECT @@binlog_format) - 表不能有外键约束(
SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME='t' AND CONSTRAINT_SCHEMA=DATABASE()) - 不能含
FULLTEXT或SPATIAL索引 -
innodb_file_per_table必须为ON(SELECT @@innodb_file_per_table) - 待建索引列不能是
TEXT/BLOB且未指定前缀(如ADD INDEX idx_c (content(191))合法,ADD INDEX idx_c (content)不合法)
漏查任意一项,执行时就会卡在 Waiting for table metadata lock 或报错 ALGORITHM=INPLACE is not supported...。
联合索引字段顺序写错会完全失效
顺序不是按业务习惯排,而是按查询模式和区分度定。一旦放反,EXPLAIN 会显示 type: ALL,等于没建。
正确排序原则:
- 等值查询(
=、IN)列优先,区分度高的放最左(如user_id比status更适合作首列) - 范围查询(
>、BETWEEN、LIKE 'abc%')列只能放最后,它右边的列无法命中索引 - 避免把
datetime放前面而user_id放后面——即使查询带WHERE user_id = ? AND created_at > ?,也只用到user_id单列部分
示例:ALTER TABLE orders ADD INDEX idx_user_status_time (user_id, status, created_at), ALGORITHM=INPLACE, LOCK=NONE; —— 若常查 WHERE status = 'paid' AND created_at > '2025-01-01',这个顺序就无效。
为什么加完索引查询还是慢?可能被 buffer pool 挤出了
大表建索引过程本身不锁表,但会大量读取主键索引页、构建 B+ 树,引发严重 I/O 和内存压力。常见现象是:索引建完,EXPLAIN 显示走了索引,但 SELECT 响应时间反而变长。
原因:
- 索引构建期间,大量数据页进入
innodb_buffer_pool,把热数据页挤出去 - 从库重放索引构建逻辑需数分钟,期间复制延迟飙升(
Seconds_Behind_Master突增),主从不一致窗口扩大 -
innodb_online_alter_log_max_size过小(默认 128MB),超限后 DDL 中断并回滚,磁盘写满风险高
应对动作:
- 避开业务高峰执行,尤其注意从库延迟是否已 > 5s
- 执行前调大
innodb_online_alter_log_max_size(如设为 512M) - 监控
SHOW ENGINE INNODB STATUS中的LOG部分,确认 online log 是否频繁 flush
ALGORITHM=INPLACE 失败了,该切 pt-osc 还是 gh-ost?
优先选 gh-ost,不是因为更“高级”,而是它对失败场景更透明、可控性更强。
pt-online-schema-change 的硬伤:
- 依赖触发器,若表已有自定义触发器,直接报错退出
- chunk 分片逻辑在大表上容易失衡,某 chunk 扫描过久导致主从延迟雪崩
- 切换
RENAME那一刻仍需短暂元数据锁,虽短但不可控
gh-ost 的优势点:
- 不依赖触发器,靠 binlog 解析+异步应用变更,无冲突风险
- 支持暂停/恢复、动态调节 chunk size、实时查看迁移进度(
_ghc表) - 切换阶段通过原子
RENAME+DROP完成,失败可立即回退,不影响原表
但注意:gh-ost 要求表必须有主键或唯一非空索引,且 binlog_format=ROW,否则启动即失败。
真正难的不是选哪个工具,而是判断这张表当前有没有隐性外键、有没有被长事务 hold 住 MDL、有没有 NULL 主键——这些都得在执行前人工确认,工具不会替你兜底。











