myisam表级锁导致多核无法并行写入,innodb行级锁+mvcc实现真正并发;myisam的count(*)优化掩盖其并发统计缺陷,而innodb通过索引、并行查询等提升扩展性;主键与索引设计才是多核性能瓶颈根源。

MyISAM的表级锁直接阻塞所有核上的并发写入
MyISAM只支持表级锁,任何 INSERT、UPDATE、DELETE 操作都会对整张表加写锁。这意味着:即使你有 32 核 CPU,只要两个线程同时尝试写同一张 MyISAM 表,其中一个必须等待——其余 30 个空闲核心完全无法参与该表的写处理。
常见错误现象:SHOW PROCESSLIST 中大量线程卡在 Waiting for table level lock;INSERT QPS 不随 CPU 核数增加而提升,反而在并发 >10 时出现断崖式延迟。
- MyISAM 的锁是内核级互斥量(mutex),争用热点集中在单个内存地址上,多核反而加剧缓存行失效(false sharing)
- 没有 MVCC,读操作(
SELECT)在写锁期间也被阻塞,进一步拉低整体吞吐 - 即使使用
INSERT DELAYED(已从 MySQL 5.6+ 移除),也无法绕过表锁本质
InnoDB 的行级锁 + MVCC 让多核真正并行工作
InnoDB 的行级锁只锁定 WHERE 条件命中且满足索引条件的行(注意:非主键/非唯一索引的 WHERE 可能升级为间隙锁甚至全表扫描锁)。配合 MVCC,多数 SELECT 完全不加锁,读写互不阻塞。
真实压测中,InnoDB 在 16 核机器上 QPS 可随并发线程数线性增长至 2000+;而同配置 MyISAM 在并发写入达 50 时,锁队列就开始堆积,CPU 利用率却长期低于 40%。
- 缓冲池(
innodb_buffer_pool_size)按页分片,多核可并行访问不同数据页,无锁竞争 - 重做日志(
redo log)写入通过log buffer批量提交,避免每事务一次磁盘同步 - 若用 UUID 或随机字符串作主键,会破坏聚簇索引局部性,导致页分裂严重——这会反向削弱多核优势,务必用自增整型或时间有序 ID
MyISAM 的 COUNT(*) 优化反而成了多核扩展的绊脚石
MyISAM 维护了表级行数计数器,所以 SELECT COUNT(*) FROM t 极快。但这看似优点的设计,掩盖了它无法支持“带条件的并发统计”的事实——一旦加上 WHERE,就必须全表扫描;而多个这样的查询并发执行,又回到表锁排队。
InnoDB 虽然 COUNT(*) 默认走索引遍历(无 WHERE 时仍需扫主键 B+ 树),但它能利用二级索引(如 COUNT(非空列))、覆盖索引、以及并行查询(MySQL 8.0.30+ 的 parallel_query hint)来摊薄开销。
- MyISAM 的计数器是全局变量,每次写操作都要原子更新——高并发下成为 CPU 缓存同步瓶颈
- InnoDB 的统计值本身是“估算”(
SHOW TABLE STATUS),但业务需要精确值时,应设计物化统计表或定时汇总,而非依赖引擎原生 COUNT
真正限制多核扩展的从来不是引擎本身,而是你的主键和索引设计
很多人把多核性能差归咎于 MyISAM 或 InnoDB,实际瓶颈常在建表阶段就埋下了:没主键的 InnoDB 表会用隐藏 row_id,导致二级索引回表变慢;MyISAM 上用复合索引做 AUTO_INCREMENT,但写入顺序混乱,加剧磁盘寻道。
一个被忽略的关键点:MyISAM 的 .MYI 索引文件是单文件结构,所有索引项共享同一把文件锁;而 InnoDB 的独立表空间(innodb_file_per_table=ON)让每个表的 I/O 路径可分散到不同磁盘或 NVMe namespace,天然适配多队列 SSD 和现代存储栈。
- 别为了“快一点的 COUNT”选 MyISAM,代价是放弃整个并发模型
- 线上环境哪怕只有一张 MyISAM 表,也可能因
REPAIR TABLE或OPTIMIZE TABLE触发长时表锁,拖垮全部业务线程 - MySQL 8.0 已将系统表全部迁至 InnoDB,MyISAM 仅保留兼容层——这意味着它的内核路径不再享受新硬件特性(如 AVX-512 加速的 CRC 校验)











