会,ALTER TABLE ... ENGINE=InnoDB 在 MySQL 5.7/8.0 下默认触发全表拷贝,期间加 DML 写锁,INSERT/UPDATE/DELETE 被阻塞,SELECT 通常可读;MyISAM→InnoDB 不支持 ALGORITHM=INPLACE,必须 COPY,耗时长且需双倍磁盘空间。

ALTER TABLE ... ENGINE=InnoDB 会锁表吗
会,而且是**全表 DML 锁**(写锁),在转换过程中,INSERT、UPDATE、DELETE 都会被阻塞,SELECT 通常还能读(取决于隔离级别和 MySQL 版本)。5.6+ 支持 ALGORITHM=INPLACE 的部分场景,但 MyISAM → InnoDB **不支持 INPLACE**,必须走 COPY 算法。
- MySQL 5.7/8.0 下,
ALTER TABLE t ENGINE=InnoDB默认触发表拷贝,期间原表只读(DML 不可用) - 如果表有 10GB,转换可能持续数分钟到几十分钟,业务高峰期务必避开
- 磁盘空间需额外预留 ≥ 原表大小(临时文件 + 新表)
- 建议先在从库或低峰期测试,用
SHOW PROCESSLIST观察状态是否卡在copy to tmp table
执行前必须检查的三个兼容性点
MyISAM 和 InnoDB 行为差异大,直接改引擎可能让应用出错,不是语法通过就万事大吉。
-
FULLTEXT索引:MyISAM 支持,InnoDB 5.6+ 才支持,且分词行为不同;若存在,ALTER会失败,需先DROP INDEX或升级 MySQL - 表名大小写:MyISAM 在 Windows 上不区分大小写,InnoDB 受
lower_case_table_names影响更严格;若应用里混用user和User,可能查不到表 - 自增列要求:InnoDB 要求
AUTO_INCREMENT列必须是索引的一部分(通常是主键或含主键的联合索引),而 MyISAM 没这限制;若原表只有id INT AUTO_INCREMENT但没建索引,ALTER会报错ERROR 1075
怎么安全地批量转换多个 MyISAM 表
别手敲十几条 ALTER TABLE,容易漏、难回滚、无法监控进度。用脚本生成 + 分批执行更可控。
- 先查出所有 MyISAM 表:
SELECT CONCAT('ALTER TABLE `', table_schema, '`.`', table_name, '` ENGINE=InnoDB;') FROM information_schema.tables WHERE engine='MyISAM' AND table_schema NOT IN ('mysql','information_schema','performance_schema'); - 导出语句到文件后,**手动删掉明显不能转的表**(比如日志表、带
FULLTEXT的旧搜索表) - 每条
ALTER后加SLEEP(1)(用SELECT SLEEP(1)),避免并发压力过大 - 生产环境建议单表执行,配合
pt-online-schema-change(需额外安装),它能绕过锁表,但要求有主键且不支持 MyISAM 源表——所以得先在从库转成 InnoDB 再用 pt 工具同步回主库
转换后必须验证的两件事
引擎改完不代表万事大吉,InnoDB 的事务、锁、崩溃恢复机制会让行为变“严谨”,有些原来能跑的 SQL 会暴露问题。
- 检查
SELECT COUNT(*)性能:MyISAM 存行数缓存,秒出;InnoDB 需扫描索引,大表可能变慢;如果业务真依赖这个,考虑加汇总表或用近似值TABLE_ROWS(来自information_schema.tables,不精确但快) - 跑一次
SELECT+UPDATE混合事务:MyISAM 是表级锁,UPDATE不影响其他SELECT;InnoDB 是行级锁,但若WHERE条件没走索引,会升级为锁全表 —— 这时老 SQL 可能突然卡住或死锁,得补上缺失索引
真正麻烦的从来不是那条 ALTER TABLE 语句,而是它揭开的那些被 MyISAM 宽容掩盖了多年的查询和设计问题。


















