alter table ... engine=innodb 会全表dml锁,因mysql不支持跨引擎online ddl,本质是重建表;大表须用pt-online-schema-change或手工迁移,转换后需验证fulltext、row_format等兼容性。

直接执行 ALTER TABLE table_name ENGINE = InnoDB 会锁表,且是全表 DML 锁——所有 INSERT/UPDATE/DELETE 都会被阻塞,SELECT 一般不受影响(取决于隔离级别)。这不是“慢”,而是“不可并发写”,线上大表必须规避。
ALTER TABLE ENGINE=... 为什么会锁表?
MySQL 不支持跨引擎的 Online DDL,ENGINE 变更本质是重建整张表:逐行拷贝数据、重建索引、替换 .frm 和 .ibd 文件。哪怕原表已是 InnoDB,只要显式执行 ENGINE=InnoDB,仍走 copy 流程。
- 5.6+ 的
ALGORITHM=INPLACE对 ENGINE 切换无效;8.0.29+ 的LOCK=SHARED仅允许并发读,写依然被锁 - MyISAM → InnoDB 转换时,若原表无主键且含自增列,语句会直接失败(InnoDB 要求自增列必须是索引一部分)
- 外键约束会触发额外检查:目标引擎不支持外键(如切到 MyISAM),则外键定义被静默丢弃;切到 InnoDB 时,关联字段必须已有索引,否则报错
ERROR 1005
执行前必须检查的三件事
别跳过验证,很多问题在 ALTER 过程中才暴露,但已无法回退。
- 运行
SHOW CREATE TABLE table_name,确认:AUTO_INCREMENT字段是否在主键或联合索引最左前缀;是否有FULLTEXT索引(MyISAM 支持,InnoDB 需 5.6+ 且需手动重建);是否存在隐式主键依赖(如非空唯一索引被自动选为主键) - 查
SELECT ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'db' AND TABLE_NAME = 'table_name',确认当前引擎;再执行SHOW ENGINES,确保目标引擎的SUPPORT列不是NO或被disabled_storage_engines禁用 - 检查磁盘空间:转换过程可能临时占用双倍空间(原表 + 新表),
df -h看/var/lib/mysql所在分区剩余空间是否 ≥ 表大小 × 2
大表(>1GB)千万别直接 ALTER
锁表时间与数据量正相关,10GB 表在普通 SATA 盘上可能锁 20 分钟以上。这时原生命令不是“方案”,而是风险源。
- 优先用
pt-online-schema-change:命令形如pt-online-schema-change --alter "ENGINE=InnoDB" D=db,t=table --execute,它通过影子表 + 触发器实现“伪在线”,但要求原表有主键或唯一非空索引,且用户需具备TRIGGER权限 - 手工建表迁移更可控:先
CREATE TABLE new_table LIKE old_table,再ALTER TABLE new_table ENGINE = InnoDB,然后分批INSERT INTO new_table SELECT * FROM old_table WHERE id BETWEEN x AND y,最后RENAME TABLE old_table TO old_bak, new_table TO old_table - 避免用
mysqldump导出导入:它默认加DROP TABLE,若中间出错易丢数据;且导出文件可能因字符集或ROW_FORMAT兼容性问题导致重建失败
转换后最容易被忽略的兼容性问题
引擎变了,行为未必一致。尤其从 MyISAM 切 InnoDB 后,以下点不验证就上线,大概率出线上事故:
-
FULLTEXT查询结果可能不同:MyISAM 停用词列表和分词逻辑与 InnoDB 不完全一致,MATCH ... AGAINST返回的匹配权重、排序顺序都可能变化 -
TEXT/BLOB字段存储方式切换:MyISAM 存行内,InnoDB 默认页外存储(off-page),单行长度计算逻辑变,可能触发Row size too large报错 -
auto_increment值虽通常延续,但若原表是 MyISAM 且 MySQL 版本 ≤ 5.5,偶发丢失;建议切完立刻SELECT MAX(id)校验 -
ROW_FORMAT隐式变更:MyISAM 表无此概念,InnoDB 会按版本默认设为DYNAMIC或COMPACT,若旧应用依赖特定行格式(如某些备份工具),需显式指定ROW_FORMAT=DYNAMIC











