myisam表锁导致的并发写入瓶颈必须迁移到innodb解决,因其表级锁为硬编码实现,不支持行锁,索引和sql优化均无效;迁移需验证事务提交、全文索引差异及“先查再更”逻辑,并监控行锁平均时间和缓冲池命中率。

MyISAM 表锁导致的并发写入瓶颈,没有参数或 SQL 优化能绕过去,必须迁移到 InnoDB。所有“调 concurrent_insert”“设 low_priority_updates”的做法,上线后一压就崩。
为什么 MyISAM 的表锁根本没法优化
MyISAM 的 LOCK TABLES WRITE 是硬编码级的全表排他锁——哪怕你只 UPDATE 一行,整张表其他读写全部排队。这不是锁得“不够细”,是它压根没实现行锁能力。
常见误判包括:
- 看到
Waiting for table level lock就去优化 SQL,其实日志里出现这句,基本等于宣告引擎选错了 - 给 MyISAM 表加了主键、唯一索引,仍无法避免锁表——索引对它的锁机制完全不生效
- 想用
SELECT ... FOR UPDATE控制并发?MySQL 直接报错ERROR 1036 (HY000): Table 't' is read only
迁移前必须验证的三件事
执行 ALTER TABLE t ENGINE=InnoDB 只是第一步,漏掉下面任一环节,上线后可能更卡:
-
autocommit默认开启,但业务代码若依赖 MyISAM “改完立刻可见”,而没显式COMMIT,切换后事务一直挂着,查不到数据、连接池慢慢耗尽 - 原表有
FULLTEXT索引,InnoDB 的分词逻辑、停用词列表不同,搜索结果可能大面积偏移,不能只比数量,要实测关键词召回率 - MyISAM 允许
INSERT和SELECT并发,InnoDB 在REPEATABLE READ下普通SELECT走 MVCC 快照读,但“先查再更”若没加FOR UPDATE,可能丢更新或幻读
迁移后最容易踩的锁陷阱
InnoDB 行锁不是自动生效的,它严格依赖索引。没索引 or 索引失效 = 锁全表(准确说是锁所有聚簇索引页):
-
UPDATE t SET status = 1(无WHERE)→ 锁全表 -
WHERE phone = '138'但phone字段没索引 → 全表扫描,每行加 X 锁 -
WHERE name LIKE '%abc'→ 索引失效,同样退化为全表加锁
务必对所有 DML 语句跑一遍 EXPLAIN,尤其关注 type 是否为 range/ref,key 是否显示用了哪个索引。
上线后必须盯住的两个监控指标
迁移不是终点,是观察期开始:
-
innodb_row_lock_time_avg:持续高于50ms,说明行锁争抢严重,大概率是缺失索引或锁范围过大 -
Innodb_buffer_pool_read_requests与Innodb_buffer_pool_reads的比值:后者占比 >1%,说明缓冲池命中率不足,innodb_buffer_pool_size可能设小了
真正难的不是 ALTER TABLE 那条命令,而是把 MyISAM 时代“不加索引也跑得动”的惯性,替换成 InnoDB 下每一处 WHERE、JOIN、ORDER BY 都要经得起 EXPLAIN 推敲。











