现代mysql生产集群中禁用myisam,因其在高可用、崩溃恢复、复制一致性三方面全部失效,主从切换或重启后常报“table is marked as crashed”或“got error 127”。

现代 MySQL 生产集群中不能用 MyISAM,不是“不推荐”,而是它在高可用、崩溃恢复、复制一致性这三个刚性要求上全部失效——只要集群发生一次主从切换或实例重启,MyISAM 表大概率直接报 Table is marked as crashed 或 Got error 127 from storage engine。
MyISAM 在主从切换后必崩的底层原因
MySQL 高可用集群(如 MHA、Orchestrator、InnoDB Cluster)依赖事务一致性、崩溃可恢复性和 binlog 精确重放。MyISAM 全部不满足:
- 没有
redo log和undo log,主库宕机时未刷盘的写操作丢失,从库提升为主库后,数据与索引文件(.MYD和.MYI)已不同步 - MySQL 8.0+ 默认
binlog_format=ROW,但 MyISAM 不支持行格式日志,自动退化为STATEMENT模式,导致NOW()、UUID()等函数在主从产生不同值 - 部分 8.0.33+ 版本在启动时检测到
mysql库含 MyISAM 表(如mysql.columns_priv),会直接拒绝加载,报错ER_UNKNOWN_STORAGE_ENGINE
ALTER TABLE ENGINE=InnoDB 的实操陷阱
把老表转成 InnoDB 不是执行一条命令就完事,容易踩坑:
-
ALTER TABLE t ENGINE=InnoDB是全量拷贝 + 重建索引 + 重写聚簇结构,千万级表需预留约 1.5 倍磁盘空间,且全程锁表 -
FLOAT/DOUBLE字段在某些 MySQL 版本中,InnoDB 会拒绝NULL值,需先ALTER COLUMN ... SET DEFAULT 0 - 若原表有
AUTO_INCREMENT,转换后自增值可能重置;建议导出前查SELECT AUTO_INCREMENT FROM information_schema.TABLES记录起点 - 不要用
mysqldump --single-transaction备份 MyISAM 表——该参数对 MyISAM 无效,必须加--lock-tables,否则备份逻辑不一致
禁用 MyISAM 后仍可能漏掉的建表路径
disabled_storage_engines=MyISAM 能拦截显式建表,但以下场景仍会悄悄生成 MyISAM 表:
-
CREATE TABLE t AS SELECT * FROM myisam_table:沿用源表引擎,不校验白名单,语句照样成功 - 从旧
mysqldump文件导入时,SQL 中含ENGINE=MyISAM,服务端默认执行(尤其 5.7 备份还原到 8.0+ 环境) -
CREATE TEMPORARY TABLE在某些配置下默认使用 MyISAM,需显式指定ENGINE=InnoDB - 已有 MyISAM 表不受禁用影响,仍可读写——这意味着上线检查容易遗漏,必须主动扫描:
SELECT TABLE_SCHEMA, TABLE_NAME, ENGINE FROM information_schema.TABLES WHERE ENGINE = 'MyISAM' AND TABLE_SCHEMA NOT IN ('mysql','information_schema','performance_schema','sys');
真正难处理的不是“怎么转”,而是那些没被发现的 MyISAM 表——它们安静地躺在业务库角落,直到某次主从切换、某次断电重启,或某个凌晨的自动备份脚本运行时,才第一次爆出 error 144,而那时修复已无意义。











