MyISAM表锁在读密集型下仍会阻塞,因任意写操作(如INSERT、REPAIR TABLE、OPTIMIZE TABLE等)均触发全表独占写锁,导致后续所有读请求排队等待;即使COUNT(*)也需表无修改才能走元数据缓存,否则退化为扫描并可能引发隐式锁争用。

MyISAM表锁在读密集型下为何还会阻塞
MyISAM 在纯读场景下确实不会互相阻塞 —— 多个 SELECT 可以并发执行。但“读密集型”不等于“只有 SELECT”,只要存在任意一个写操作(哪怕只是偶尔的 INSERT 或 UPDATE),整个表就会被独占锁定,所有后续读请求都得排队等待。
哪些看似“只读”的操作实际会触发写锁
开发常误以为某些操作是安全的,其实它们隐式申请了表级写锁:
-
REPAIR TABLE、OPTIMIZE TABLE、ANALYZE TABLE这类维护命令,在 MyISAM 下默认使用写锁(即使目标表当前无写入) -
INSERT DELAYED虽已废弃,但在旧系统中仍可能残留;它不阻塞读,但会排队写,且队列本身会持有轻量级表锁 - 批量
LOAD DATA INFILE即使只插入新数据,也会先获取写锁再加载,期间所有SELECT挂起 - 任何显式
LOCK TABLES ... WRITE(比如脚本中为“保证一致性”加的锁),哪怕只持续几毫秒,也足以卡住高并发读流
MyISAM 的 COUNT(*) 快,但快的前提是没人在改
MyISAM 的 COUNT(*) 确实直接读元数据,不扫描表,但这依赖一个前提:没有其他线程正在修改该表。一旦有 INSERT 或 UPDATE 正在进行,MyISAM 会临时禁用计数器缓存,退化为实际扫描行 —— 此时不仅慢,还可能因全表扫描触发隐式读锁升级(尤其在老版本中)。更糟的是,某些监控脚本每分钟跑一次 SELECT COUNT(*) FROM t,恰好撞上业务写入高峰,就成了锁冲突放大器。
为什么 SHOW PROCESSLIST 看不到明显“卡住”,却实际在等锁
MyISAM 表锁是轻量级的,不进入 INNODB_TRX 或 INNODB_LOCK_WAITS 视图(那些只对 InnoDB 有效)。你查 SHOW PROCESSLIST 时,被阻塞的 SELECT 状态通常是 Locked 或 Waiting for table level lock,但这个状态一闪而过,容易被忽略。真正难排查的是:当多个慢查询(如未走索引的 SELECT)叠加在同一个 MyISAM 表上,它们会逐个排队抢读锁,形成“锁链式延迟”—— 第一个慢查卡住1秒,后面20个读请求就各自多等1秒以上,而每个单独看都不算超时。
MyISAM 表锁的“轻量”是双刃剑:加锁快、开销小,但也意味着它几乎不参与任何锁兼容性协商,也不支持锁降级或等待队列优化。只要有一个写意图出现,整个表就瞬间变成单点瓶颈。这点在读写混合但写频次低的场景下,比想象中更致命。


















