myisam只支持表锁,因其设计缺失事务日志、mvcc及行锁所需元数据,所有写操作须加整表互斥锁以保证一致性。

MyISAM 为什么只支持表锁
因为 MyISAM 的设计从底层就放弃了行级并发控制能力。它没有事务日志、没有 MVCC 机制、也没有行锁所需的元数据结构(比如聚簇索引中的锁信息位或内存锁队列)。所有写操作(INSERT、UPDATE、DELETE)都直接修改数据文件(.MYD)和索引文件(.MYI),必须靠整个表的互斥锁来保证一致性。
这导致一个 UPDATE 即使只改一行,也会阻塞其他线程对同一张表的任何写入,甚至部分读操作(如 ALTER TABLE 或某些 SELECT ... FOR UPDATE 等价行为)。
MyISAM 表锁 vs InnoDB 行锁的实际表现差异
在高并发写场景下,MyISAM 的表锁会迅速成为瓶颈;而 InnoDB 的行锁只锁定被修改的记录(基于聚簇索引或二级索引加锁),其余行仍可并发读写。但要注意:InnoDB 的“行锁”不是绝对安全的——如果查询没走索引,会升级为表锁;而 MyISAM 压根不区分,一律表锁。
-
SELECT COUNT(*) FROM myisam_table不加锁,但会等正在执行的写锁释放 -
SELECT * FROM innodb_table WHERE id = 123可能只锁住这一行(若id是主键) -
SELECT * FROM innodb_table WHERE name = 'xxx'若name没索引,会锁全表(ALL扫描 + 意向锁升级)
MyISAM 表锁类型与隐式行为
MyISAM 使用两种表级锁:READ 锁(共享)和 WRITE 锁(独占)。多个线程可以同时持有 READ 锁,但只要有一个 WRITE 锁在等待,后续所有 READ 请求都会排队——这是典型的“写优先”策略,容易造成读饥饿。
更隐蔽的问题是:即使你只执行 SELECT,如果该语句触发了隐式锁(比如在 INSERT DELAYED 或某些修复操作期间),也可能被挂起。另外,REPAIR TABLE、OPTIMIZE TABLE 这类维护命令会强制获取 WRITE 锁,且持续时间长,线上务必避开高峰。
切换存储引擎前必须验证的兼容点
把 MyISAM 表转成 InnoDB 并不只是执行 ALTER TABLE t ENGINE=InnoDB 就完事。你要检查:
- 是否依赖
FULLTEXT索引?MyISAM 的全文索引语法和行为与 InnoDB 不完全一致(尤其分词和停用词) - 是否有大量
INSERT ... SELECT或LOAD DATA INFILE?InnoDB 默认开启事务,可能因 autocommit 关闭导致意外长事务 - 是否使用了
AUTO_INCREMENT并发插入优化?MyISAM 允许在表尾并发INSERT,InnoDB 则需主键有序才能高效分配 ID - 磁盘空间是否足够?InnoDB 数据文件通常比 MyISAM 大 20%~50%,尤其带大文本字段时
最常被忽略的是锁等待超时设置:innodb_lock_wait_timeout 默认 50 秒,而 MyISAM 根本不报锁等待错误——切过去后突然出现大量 Lock wait timeout exceeded,往往是因为应用没做重试或死锁处理。










