alter table engine=innodb不能用于线上大表,因mysql 5.7/8.0强制使用copy算法、algorithm=inplace不生效、lock=none自动降级为exclusive锁,全程mdl写锁阻塞读写;唯一可靠方案是pt-online-schema-change,通过影子表+触发器分块同步实现无锁迁移。

ALTER TABLE ENGINE=InnoDB 为什么不能用于线上大表
这不是语法问题,是底层执行机制决定的硬限制:MySQL 5.7/8.0 对 MyISAM → InnoDB 的引擎变更仍强制走 COPY 算法,ALGORITHM=INPLACE 不生效。LOCK=NONE 会被自动降级为 LOCK=EXCLUSIVE,表全程被 MDL 写锁阻塞。
常见错误现象包括:SHOW PROCESSLIST 长期卡在 copy to tmp table;主库写入中断;从库 Seconds_Behind_Master 突然跳到数千秒;磁盘 IO 暴涨、innodb_log_waits 上升。
仅当同时满足以下条件时,才可考虑直接 ALTER TABLE:
- 表大小 ≤ 500MB(SSD 实测转换时间通常 ≤3 分钟)
- 业务允许该表在转换窗口内完全不可写(如只读配置表)
-
SHOW INDEX FROM table_name WHERE Key_name = 'FULLTEXT'返回空结果(无全文索引) -
SHOW KEYS FROM table_name WHERE Non_unique = 0 AND Seq_in_index = 1有结果(存在主键或唯一非空索引) -
df -h /var/lib/mysql显示剩余空间 ≥ 原.MYD文件大小 × 2.2
pt-online-schema-change 是目前唯一能落地的无锁方案
它不依赖 MySQL 原生 DDL,而是通过影子表 + 触发器双写同步,业务基本无感。但前提是目标表必须有主键或唯一非空索引——否则会报错 This table has no primary key or unique index。
关键参数必须显式控制节奏和容错:
-
--chunk-size=1000:每次迁移行数,大表建议调小(如 500),避免单次事务过大 -
--max-lag=1+--check-interval=5:从库延迟超 1 秒就暂停,每 5 秒检查一次 -
--chunk-time=0.5:避免默认 120 秒超时导致中断(单位是秒) -
--execute:确认无误后才加,测试阶段用--dry-run或--test-u
注意:pt-osc 迁移完成后,旧的 .MYD 和 .MYI 文件不会自动删除,必须人工清理——先跑 CHECKSUM TABLE old_table 和 CHECKSUM TABLE new_table 确认一致,再删文件。
含 FULLTEXT 索引的表怎么处理
InnoDB 5.6+ 支持 FULLTEXT,但分词规则、停用词、权重计算与 MyISAM 不同,直接转换后 MATCH AGAINST 可能查不到结果,不是 SQL 写错,是索引行为变了。
安全做法是分两步:
- 先
DROP INDEX ft_index_name ON table_name(MyISAM 全文索引名通常以ft_开头) - 用
pt-online-schema-change转为 InnoDB - 再
CREATE FULLTEXT INDEX ft_index_name ON table_name(col)重建索引
重建后务必验证查询结果是否符合预期,必要时调整 innodb_ft_min_token_size 或自定义停用词表。
转换后必须立刻调的几个配置项
引擎改完不调参等于白转。InnoDB 和 MyISAM 的内存模型完全不同:
-
innodb_buffer_pool_size设为物理内存的 50%–75%,不能沿用 MyISAM 的key_buffer_size -
key_buffer_size从几百 MB 降到32M左右(MyISAM 不再用) -
innodb_flush_log_at_trx_commit非金融场景设为2(崩溃最多丢 1 秒数据) - 确认
innodb_file_per_table=ON(MySQL 5.6+ 默认开启,但需SHOW VARIABLES LIKE 'innodb_file_per_table'实际验证)
特别注意:COUNT(*) 在 InnoDB 下不再走缓存,结果准确但变慢,若业务强依赖快速行数统计,得改用近似值或加冗余计数字段——这不是 bug,是行为差异。











