myisam 的 concurrent_insert 仅对纯 insert 尾部追加有效,delete/update/replace 及任何读操作均会中断并发能力,其本质是引擎级表锁限制,优化无效,应迁移到 innodb。

MyISAM 的 concurrent_insert 不是真正的并发插入,它只在极窄的尾部追加场景下生效,且对 DELETE/UPDATE/REPLACE 完全无效——这不是配置没开对,而是引擎设计决定的硬限制。
concurrent_insert=2 只对纯 INSERT 尾部追加有效
MyISAM 的“并发插入”本质是允许一个线程读、另一个线程往数据文件末尾(.MYD)写,前提是中间没有空洞(即没执行过 DELETE 或 UPDATE)。concurrent_insert = 2 强制启用该行为,哪怕有空洞也继续往结尾写;但一旦表里发生过任何 DELETE 或 UPDATE,MyISAM 可能重建 .MYD 文件,后续插入立刻退化为普通表锁。
常见误判:看到 SHOW PROCESSLIST 里仍有大量 Locked 状态,就以为参数没生效——其实它本就没打算覆盖所有写操作。
-
concurrent_insert = 0:完全禁用并发插入 -
concurrent_insert = 1(默认):仅当表中无空洞时才启用,业务日志表几乎不可能满足 -
concurrent_insert = 2:唯一推荐值,但仍只作用于INSERT,且不改变锁粒度
所有非 INSERT 写操作都会中断并发能力
只要执行一次 REPLACE、UPDATE 或 DELETE,MyISAM 就可能触发数据文件重排,导致后续所有 INSERT 暂时失去并发能力。即使你刚设好 concurrent_insert = 2 并重启,只要定时任务跑了一次 OPTIMIZE TABLE 或应用层发了个 UPDATE status=1 WHERE id=123,并发插入就失效了。
更隐蔽的问题:INSERT ... SELECT 或带子查询的插入,在 MyISAM 中也会被当作非纯插入处理,无法享受并发写入。
-
INSERT INTO log VALUES (...)→ 可能并发 -
REPLACE INTO log VALUES (...)→ 必锁全表 -
UPDATE log SET processed=1 WHERE id=100→ 必锁全表,且破坏后续 INSERT 并发性 -
INSERT INTO log SELECT * FROM tmp_log→ 不走 concurrent_insert 逻辑
SELECT 查询会直接阻塞所有写入
MyISAM 表级锁是“写优先”的:任意一个 SELECT COUNT(*)、SELECT MAX(id) 或监控拉取语句正在执行,所有 INSERT 都得排队等它结束。这和 concurrent_insert 设置无关——它只缓解“读+尾部插入”的冲突,不解决“读阻塞写”这个根本问题。
日志类表最容易踩坑:运维查个 SELECT COUNT(*) FROM access_log WHERE day='2026-09-03',整个写入链路就卡住几十秒。
- 禁止在日志表上执行任何聚合查询、排序、
LIKE模糊匹配 - 必须把读需求剥离到汇总表、外部存储(如 Elasticsearch)或离线导出(
SELECT ... INTO OUTFILE) - 连
SELECT id FROM log ORDER BY id DESC LIMIT 1这种看似轻量的操作,都可能因索引扫描引发锁等待
真正瓶颈不在参数,而在引擎不可绕过的锁模型
调 concurrent_insert 是在给一辆没有变速箱的车换机油——它不能解决“一写就锁全表”这个设计事实。InnoDB 的行锁机制才是应对高并发写入的正解,而 MyISAM 的优化空间早已被榨干:它不支持事务、不支持崩溃恢复、不支持外键,连 INSERT DELAYED 都已在 MySQL 5.6 中彻底移除(报错 ERROR 1064 (42000))。
如果你还在用 MyISAM 做实时日志表,最该做的不是调参,而是检查迁移 InnoDB 的阻碍点:有没有缺失主键、有没有未提交事务残留、全文索引是否需适配——这些比纠结 concurrent_insert 值重要得多。











