MyISAM并发更新必然整表阻塞,因其仅支持表级锁,任何INSERT/UPDATE/DELETE均加整表独占写锁,阻塞所有其他读写;CONCURRENT INSERT仅在无空洞且无WHERE时有限生效。

MyISAM 并发更新必然整表阻塞,不是配置问题,是引擎设计决定的。
MyISAM 只有表级锁,没有行锁概念
MyISAM 的锁粒度固定为整张表。只要执行 INSERT、UPDATE 或 DELETE,MySQL 就会立即对整张表加独占写锁(table write lock)。此时:
- 其他会话的任何
SELECT都会被挂起,等写锁释放 - 其他会话的任何写操作(哪怕只改一行)也必须排队等待
- 即使 SQL 里带了
WHERE id = 123,锁住的仍是全表,不是那行 -
CONCURRENT INSERT是唯一例外,但仅在无空洞 + 无WHERE条件时生效,实际生产中几乎不可靠
为什么 InnoDB 不会这样?关键在锁粒度
InnoDB 默认用行锁(row lock),更新某行只锁那一行,其他行照常读写。它还能自动升级锁类型:
- 命中索引 → 加记录锁(record lock)
- 范围查询未命中 → 加间隙锁(gap lock)或临键锁(next-key lock)
- 全表扫描(如没建索引)→ 会退化为表锁,但这是异常路径,不是默认行为
而 MyISAM 没有“退化”一说——它从出生就只有表锁,没得选。
怎么快速确认是不是 MyISAM 表锁导致的阻塞?
别猜,直接查状态:
- 运行
SHOW PROCESSLIST,看有没有大量线程状态为Waiting for table level lock - 查慢查询日志,如果频繁出现
Waiting for table level lock,基本就是 MyISAM 表锁瓶颈 - 用
SHOW OPEN TABLES WHERE In_use > 0查当前被锁定的表 - 注意:
information_schema.INNODB_TRX对 MyISAM 无效,别白查
ALTER TABLE ENGINE=InnoDB 前必须检查的四件事
线上改引擎不是一条命令就能跑完的事:
- 磁盘空间是否够?转换过程会先建新 InnoDB 表再拷数据,临时空间至少等于原表大小
- 主键是否存在?InnoDB 强依赖聚簇索引;若原表无主键,MySQL 会自动生成隐藏
ROW_ID,导致二级索引膨胀、范围查询变慢 - 外键约束是否允许?MyISAM 不支持外键,转 InnoDB 后需补全定义,否则
ALTER会失败 - 是否在低峰期执行?改引擎期间表不可写,且可能触发长时间元数据锁(MDL),影响所有后续 DDL/DML
真正容易被忽略的是:MyISAM 表一旦上了规模,改引擎耗时远超预期,且过程中无法回滚。与其事后抢救,不如建表时就选对引擎。


















