MyISAM 只能用表锁,因其设计哲学定位为轻量高速的只读/低写场景,刻意不支持事务、MVCC和行级锁,仅用一个表级锁状态位实现并发控制。

MyISAM 为什么只能用表锁?根本原因在设计哲学
MyISAM 没有行锁,不是“没实现”,而是**刻意不支持**——它从诞生起就定位为轻量、高速的只读/低写场景引擎,压根没引入事务、MVCC、行级锁管理这些复杂机制。它的锁结构极其简单:一个表对应一个锁状态位(READ/WRITE),所有并发控制都靠这个位和写优先队列完成。
这意味着:
- 没有 undo log,没法做行级回滚
- 没有聚簇索引,数据物理顺序和主键无关,无法高效定位单行加锁
- 索引文件(.MYI)和数据文件(.MYD)分离,加行锁需跨文件协调,违背其“快而简”的初衷
对比 InnoDB 行锁,MyISAM 表锁的实际表现差异
别只看“锁粒度大”这种结论,关键看真实行为:
-
SELECT自动加READ锁 → 其他SELECT不阻塞,但任何UPDATE/INSERT都得排队等它释放 - 一旦有写操作进入等待队列(哪怕只是
UPDATE ... WHERE id = 1),后续所有读写请求全被卡住 —— 这是 MyISAM 的**写优先调度策略**导致的,不是 bug,是设计 -
table_locks_waited状态值飙升,说明表锁争用严重;table_locks_immediate却很高?那大概率是纯读场景,MyISAM 反而比 InnoDB 更快
什么时候你其实不该用 MyISAM,哪怕它“支持全文索引”
很多人留着 MyISAM 就为 FULLTEXT,但要注意:
- InnoDB 从 MySQL 5.6 起已原生支持
FULLTEXT,语法完全兼容,且支持事务一致性 - MyISAM 的全文索引不支持停用词配置、权重调整、布尔模式中的括号嵌套等高级特性
- 备份时若用
mysqldump --single-transaction,MyISAM 表会自动退化为 FTWRL(FLUSH TABLES WITH READ LOCK),整个库只读,而 InnoDB 表不受影响 - 崩溃恢复几乎为零 ——
myisamchk修复失败率高,且必须停机
真要硬上 MyISAM 表锁,必须绕开的三个坑
如果你维护遗留系统或日志归档表,不得不碰 MyISAM,记住:
- 永远不要在业务高峰期执行
ALTER TABLE ... ENGINE=MyISAM—— 这会触发全表重建+隐式写锁,锁表时间远超预期 -
LOCK TABLES tb WRITE后,当前连接必须先UNLOCK TABLES才能执行新查询;否则报错ERROR 1100 (HY000): Table 'tb' was not locked with LOCK TABLES - MyISAM 不识别事务语句:
BEGIN/COMMIT完全无效,ROLLBACK也不报错但无作用 —— 别指望用事务包装它的写操作
表锁本身不难理解,难的是它背后那一整套放弃事务、放弃并发、放弃崩溃安全的妥协逻辑。只要写入稍有并发,MyISAM 就会暴露本质:它不是“老而稳”,而是“专而窄”。










