会锁表,且是全表dml锁;alter table t engine=innodb本质重建表,阻塞所有insert/update/delete,5.6+不支持inplace,8.0.29+可用lock=shared允许并发读但写仍阻塞。

ALTER TABLE ... ENGINE=InnoDB 会锁表吗
会,而且是全表 DML 锁(写锁),在大多数 MySQL 版本和存储引擎组合下,ALTER TABLE t ENGINE=InnoDB 是阻塞所有 INSERT/UPDATE/DELETE 的。5.6 之后的 InnoDB 支持 ALGORITHM=INPLACE,但仅限某些操作;ENGINE 转换不在此列——它本质是重建表,MySQL 必须拷贝数据、重建索引、替换.frm 和.ibd 文件。
实操建议:
- 线上表务必避开业务高峰执行,提前评估锁表时长(可通过
SELECT COUNT(*) FROM t估算数据量级) - 若用的是 MySQL 8.0.29+ 且目标引擎是 InnoDB,可尝试
ALTER TABLE t ENGINE=InnoDB ALGORITHM=COPY LOCK=SHARED,允许并发读,但写仍被阻塞 - 对大表(>10GB),优先考虑 pt-online-schema-change 或 gh-ost,它们通过影子表+触发器实现无锁变更
MyISAM 转 InnoDB 后主键和索引行为变化
MyISAM 没有聚簇索引,InnoDB 有;这个差异会导致查询逻辑、磁盘布局、甚至语义结果微调。
常见错误现象:
- 原 MyISAM 表没显式定义主键,转换后
SHOW CREATE TABLE显示自动添加了隐式PRIMARY KEY (id)(如果存在非空唯一索引)或报错“Table has no primary key”(严格模式下) - 全文索引(FULLTEXT)在 MyISAM 中支持,在 InnoDB 中需 5.6+ 且建表时显式指定,转换后不会自动保留
- 自增字段行为更严格:InnoDB 要求自增列必须是索引的一部分(通常是主键或联合索引最左前缀),否则
ALTER TABLE ... ENGINE=InnoDB会失败
实操建议:
- 转换前先跑
SHOW CREATE TABLE t,检查是否有隐式主键依赖、FULLTEXT 索引、自增列是否合规 - 若原表无主键且含自增列,必须先
ALTER TABLE t ADD PRIMARY KEY (id)再改引擎 - 全文索引需手动重建:
ALTER TABLE t DROP INDEX ft_col, ADD FULLTEXT INDEX ft_col (col)
修改 ENGINE 时 utf8mb4 和 ROW_FORMAT 兼容性问题
ENGINE 变更本身不改字符集或行格式,但 InnoDB 对 ROW_FORMAT 有默认策略,而旧 MyISAM 表可能用了过时的 ROW_FORMAT=COMPACT 或未显式设置,导致转换后出现警告甚至插入失败。
使用场景:
- MySQL 5.7.9+ 默认
innodb_file_format=Barracuda+innodb_large_prefix=ON,才支持ROW_FORMAT=DYNAMIC和长索引(>767 字节) - 若原表字段含
VARCHAR(2000)且字符集为utf8mb4,InnoDB 默认COMPACT格式下索引长度超限,ALTER TABLE ... ENGINE=InnoDB会报错Specified key was too long
实操建议:
- 转换前确认全局配置:
SELECT @@innodb_file_format, @@innodb_large_prefix - 显式指定安全的行格式:
ALTER TABLE t ENGINE=InnoDB ROW_FORMAT=DYNAMIC - 如遇索引超长,临时缩短字段(如
VARCHAR(191))或删掉冗余索引再转,后续再优化
如何验证 ENGINE 修改成功且数据一致
别只信 Query OK,ENGINE 转换失败时 MySQL 有时静默回退或部分生效(尤其遇到权限、磁盘满、中断等情况)。
实操建议:
- 立刻查元数据:
SELECT ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA='db' AND TABLE_NAME='t',确认返回InnoDB - 对比行数:
SELECT COUNT(*) FROM t转换前后必须一致;若差一行,很可能是转换中途被 kill,表处于半重建状态(此时应从备份恢复) - 抽样校验数据完整性:选一个带索引的字段,
SELECT MIN(id), MAX(id), COUNT(DISTINCT id) FROM t,确保无缺失、无重复(MyISAM 崩溃后可能有重复自增值,InnoDB 会拒绝插入) - 检查错误日志:
tail -n 50 /var/log/mysql/error.log,搜ERROR或Warning,特别是Failed to open table类提示
真正麻烦的不是命令敲错,而是以为改完了,其实只改了表结构没搬数据,或者搬了一半就停了——这种表外表正常,内里已损坏,上线后才暴露。所以每次改完,至少盯住 count 和 error log 两分钟。











