MyISAM 引擎因缺乏崩溃恢复机制、无事务支持、表级锁及外键约束失效等问题,已不适用于生产环境。MySQL 8.0 起系统表全迁 InnoDB,MyISAM 被官方弃用并标记为 deprecated。

MyISAM 表在崩溃后无法自检,连“自己坏了都不知道”
MyISAM 没有 redo log 和 undo log,所有写操作直接刷盘到 .MYD(数据)和 .MYI(索引)文件。断电、OOM 或 MySQL 被 kill 后,两个文件极易错位:索引计数和实际行数对不上、SELECT COUNT(*) 和 SELECT * FROM t WHERE id > 1000 返回矛盾结果。更危险的是——MySQL 不报错,也不告警,业务照常读写,但数据逻辑已经错乱。
常见现象包括:
-
Table is marked as crashed and should be repaired频繁出现,但REPAIR TABLE只是暴力重建索引,不验证业务一致性 - 主从复制中,从库执行完
REPLACE INTO看似成功,金额/状态却已错位,且无任何 binlog 错误日志可查 - mysqldump --single-transaction 对 MyISAM 表退化为全局
FLUSH TABLES WITH READ LOCK,整个库写入阻塞
MyISAM 的“原子性”只骗自己,根本扛不住业务逻辑
所谓 MyISAM “单条语句原子”,仅指一条 UPDATE 不会改半行;但它完全不保证多语句事务逻辑。比如转账场景:UPDATE account SET balance = balance - 100 WHERE id = 1 和 UPDATE account SET balance = balance + 100 WHERE id = 2 必须成对成功或失败。MyISAM 下前一条成功、后一条失败,资金就凭空蒸发。
而 InnoDB 用 BEGIN/COMMIT 包裹,靠 undo log 保障整体回滚。更关键的是:
-
FOREIGN KEY语法在 MyISAM 中被忽略,外键约束形同虚设 -
INSERT ... ON DUPLICATE KEY UPDATE实际执行为“先删后插”,自增 ID 跳变,且删除与插入无法原子化 -
SELECT ... FOR UPDATE在 MyISAM 中被静默忽略,应用层以为加了锁,其实并发写入仍在发生
高并发下表级锁直接卡死核心链路
MyISAM 任何写操作(INSERT/UPDATE/DELETE)都对整张表加排他锁,期间所有读请求也得排队。更糟的是写锁优先级高于读锁:已有 10 个 SELECT 在等,一个新来的 INSERT 会插队,导致读请求长时间饥饿。
线上真实踩坑点:
- 用户中心表被一条慢
UPDATE卡住,连带影响登录、鉴权等核心链路 - InnoDB 的行级锁只在 WHERE 条件走索引时生效;若没索引(如
WHERE status = 1),也会升级为表锁——但这属于用法问题,不是引擎缺陷 - MyISAM 表级锁在分库分表、读写分离、多活架构下天然失效,中间件(如 ShardingSphere)不解析其内部逻辑,硬编码表名直接绕过路由规则
MySQL 8.0 已彻底弃用 MyISAM,系统表全量迁入 InnoDB
MySQL 8.0 所有系统表(mysql.user、mysql.db、performance_schema 等)强制使用 InnoDB。这不是“优化”,而是“不换就崩”:MyISAM 系统表崩溃后,REPAIR TABLE 修复成功率极低,连 SELECT USER() 都可能失败,实例直接失去访问控制。
官方态度非常明确:
-
SHOW ENGINES输出中 MyISAM 的 Comment 字段写着deprecated, not encouraged - MySQL 8.0+ 手册里,“MyISAM”仅出现在
Deprecated Features章节,不再提供独立运维指南 -
disabled_storage_engines="MyISAM"启用后,CREATE TABLE ... ENGINE=MyISAM直接报ERROR 3161,但CREATE TABLE t AS SELECT * FROM myisam_table仍会生成 MyISAM 表——因为沿用源表引擎,不校验白名单
真正容易被忽略的是:MyISAM 的“可用”往往只存在于测试或初期阶段;等数据量上来、业务逻辑变复杂、故障真实发生时,修复成本远高于初期转换引擎的成本。


















