超大表(>10GB)必须放弃ALTER TABLE,因其强制使用COPY算法,全程持MDL写锁阻塞所有DML、耗尽磁盘空间、拖垮主从;唯一安全方案是pt-online-schema-change,但需满足主键/唯一索引、innodb_file_per_table=ON、主从延迟为0等硬性前提。

不能用 ALTER TABLE t ENGINE=InnoDB,它在超大表上必然锁写、吃光磁盘、拖垮主从——所谓“在线”只是最后几毫秒元数据切换,拷贝过程全程阻塞,停机风险极高。
为什么超大表(>10GB)必须放弃 ALTER TABLE?
MySQL 8.0 仍强制对 MyISAM → InnoDB 使用 COPY 算法,不是语法问题,是内核限制。你看到的 copy to tmp table 状态,就是真实在搬数据:
- 全程持有 MDL 写锁:所有
INSERT/UPDATE/DELETE被拒绝,部分SELECT在REPEATABLE-READ下也会卡住 - 磁盘空间需 ≥ 原
.MYD+.MYI总大小 × 2.2:含 redo log 增长、临时排序文件、ibdata1 预留 - 主库执行时,binlog 积压;从库回放同样要等锁释放,
Seconds_Behind_Master可能跳到数小时 - 即使加
LOCK=NONE,MySQL 会自动降级为LOCK=EXCLUSIVE,不接受协商
唯一可行方案:pt-online-schema-change(pt-osc)
它通过影子表 + 触发器双写实现业务无感,但不是“开箱即用”,必须满足硬性前提:
- 表必须有主键或唯一非空索引,否则报错
This table has no primary key or unique index -
innodb_file_per_table = ON(5.6+ 默认开启,检查SHOW VARIABLES LIKE 'innodb_file_per_table';) - 主从延迟为 0(
Seconds_Behind_Master = 0),否则影子表数据滞后 - 先
DROP INDEX ft_idx ON t;清掉 MyISAM 的FULLTEXT索引(pt-osc 不支持迁移全文索引)
典型命令:
pt-online-schema-change \ --alter "ENGINE=InnoDB" \ D=your_db,t=big_table \ --execute \ --chunk-size=500 \ --max-lag=1 \ --check-interval=5 \ --critical-load="Threads_running=25"
注意:--chunk-size 要根据单行平均大小调小(比如宽表建议 100–300),避免单次事务过大触发 innodb_log_file_size 溢出。
转换后必须人工验证和清理
pt-osc 完成后不会自动删旧文件,也不保证语义等价:
- 手动比对
COUNT(*)和关键字段聚合值(如SUM(amount)),不能只信行数 - 检查外键:MyISAM 忽略
FOREIGN KEY定义,InnoDB 会校验——若存在脏数据,转换后首次INSERT就报ERROR 1452 - 旧
.MYD/.MYI文件不会自动删除,确认新表数据一致后,再执行rm /var/lib/mysql/your_db/big_table.{MYD,MYI} - 全文检索必须重测:
MATCH(col) AGAINST('+apple -orange' IN BOOLEAN MODE)在 InnoDB 中括号嵌套行为不同,部分表达式会静默失效
最易被忽略的是:转换后 innodb_buffer_pool_size 若没调大,InnoDB 表反而比 MyISAM 更慢;而 key_buffer_size 若没同步调小,内存会被两套缓存争抢——引擎变了,配置不调等于白转。


















