concurrent_insert=2必须在my.cnf中配置并重启mysql才生效,动态set无效;该参数仅对myisam表尾部追加有效,delete产生的空洞、非insert语句及未用read local锁的select均会阻塞并发插入。

concurrent_insert=2 必须在 my.cnf 里配,SET 不生效
MySQL 的 concurrent_insert 是个只读系统变量,动态 SET GLOBAL concurrent_insert = 2 会静默失败或报错(取决于版本),实际值不会变。必须编辑 MySQL 配置文件:/etc/my.cnf 或 /etc/mysql/my.cnf,在 [mysqld] 段落下添加:
concurrent_insert = 2
改完后必须重启 MySQL 服务,例如:/etc/init.d/mysqld restart 或 systemctl restart mysqld。重启后执行 SHOW VARIABLES LIKE 'concurrent_insert'; 确认返回值是 2。
并发插入只对尾部追加有效,DELETE 后的空洞不触发并发
MyISAM 的并发插入不是“多线程同时写任意位置”,它只允许新行追加到数据文件末尾(.MYD 文件尾部)。即使设了 concurrent_insert = 2,只要 INSERT 语句试图复用表中间的删除空洞(比如执行过 DELETE FROM log_table WHERE id ),就会退化为普通表级写锁,阻塞所有 SELECT。
- 日志类表应避免 DELETE,用分区或归档迁移代替
- 如果已有空洞,可定期执行
OPTIMIZE TABLE log_table收回空间,但该操作会锁表,需安排在低峰期 -
INSERT ... SELECT、REPLACE、UPDATE全都不走并发路径,哪怕只改一行也会中断后续并发插入能力
READ LOCAL 锁才能让 SELECT 不阻塞 INSERT
默认情况下,一个长时 SELECT(比如 SELECT COUNT(*) FROM log_table)会持有表级读锁,导致所有 INSERT 排队等待。要真正实现读写并发,应用层必须显式使用 LOCK TABLE log_table READ LOCAL,而不是 READ。
-
READ LOCAL允许其他连接在表尾并发插入,但当前会话查不到这些新数据(MVCC 缺失的体现) -
READ锁则完全禁止任何写入,包括并发插入 - InnoDB 表上
READ LOCAL和READ行为一致,不支持该特性
真正瓶颈从来不是 concurrent_insert 值,而是 SELECT 干扰和单包大小
调成 concurrent_insert = 2 只是必要条件,不是充分条件。线上日志表吞吐卡住,90% 情况下是因为:
- 监控脚本或后台任务执行了未加索引的
SELECT,持续占用读锁 - 单次
INSERT包含上千行,触发max_allowed_packet限制或网络超时 - 表上有非必要索引(如对
user_id建了唯一索引),每次插入都要校验并更新索引树
比纠结配置值更关键的是:剥离读操作、用批量插入(每批 ≤ 500 行)、禁用除时间字段外的所有索引。这些动作带来的提升,远超反复调整 concurrent_insert。











