concurrent_insert=2能缓解MyISAM写阻塞,但仅限于向表末尾追加INSERT且与SELECT并发的场景;它不解决UPDATE、DELETE或空洞填充类写操作的锁表问题。

concurrent_insert=2 能缓解 MyISAM 写阻塞吗
能,但只对特定场景有效:当写操作是向表末尾追加(INSERT),且读操作同时进行时,concurrent_insert=2 允许读和插入并行。它不解决 UPDATE、DELETE 或中间有空洞的 INSERT 引发的锁表问题。
本质是绕开“写锁阻塞读”的默认行为,不是消除锁本身——MyISAM 仍会对写操作加全表写锁,只是把“允许并发读+追加写”从例外变成常态。
-
concurrent_insert=0:完全禁用并发插入,所有INSERT都要等当前读完成 -
concurrent_insert=1(默认):仅当表没空洞(即没执行过DELETE或UPDATE导致行删除)时,才允许末尾并发插入 -
concurrent_insert=2:不管有没有空洞,只要INSERT是追加到文件末尾,就读写并发
为什么 SHOW PROCESSLIST 里还是看到 Locked 状态
因为 concurrent_insert 只影响 INSERT 和 SELECT 的并行性,不影响其他写操作。如果你看到线程 State 是 Locked,大概率是下面之一:
- 正在执行
UPDATE或DELETE—— 这些操作必然锁全表,concurrent_insert完全不生效 - 执行了
ALTER TABLE或OPTIMIZE TABLE—— 这些是 DDL,强制全表锁,且持续时间长 - 有显式
LOCK TABLES t WRITE未释放 —— 这种手动锁不受concurrent_insert控制 - 虽然用了
concurrent_insert=2,但INSERT实际触发了空洞填充(比如INSERT ... SELECT或带WHERE的批量插入),此时仍会退化为普通写锁
concurrent_insert 配置后还要注意什么
这个参数是会话级 + 全局级双生效的,但容易被忽略几个细节:
- 必须在 MySQL 启动时或运行时通过
SET GLOBAL concurrent_insert = 2设置;仅SET SESSION不起作用,因为它是全局行为开关 - 修改后新连接立即生效,但已有连接不会自动继承,需重连或显式
SET SESSION - 即使设为 2,如果表上有
FULLTEXT索引,某些版本(如 5.6)在插入时仍可能短暂升级为全表锁,需实测验证 - 并发插入产生的数据文件碎片会随时间增长,建议搭配定期
OPTIMIZE TABLE(注意:该命令本身会锁表,应选低峰执行)
真正卡住写并发时,别只调 concurrent_insert
如果你观察到 Table_locks_waited 持续升高,或者 SHOW PROCESSLIST 里大量线程卡在 Waiting for table level lock,说明瓶颈不在插入并发,而在写操作本身太重或太频繁。
这时更关键的动作是:
- 拆分大批次写入:把单条含 10000 行的
INSERT INTO ... VALUES (),(),...改成每批 500 行,减少单次锁表时间 - 避免在写密集场景混用 MyISAM 和 InnoDB 表——MyISAM 不参与事务,但会让整个连接无法及时释放,拖慢后续语句
- 检查是否误用了
LOW_PRIORITY:它让写让路,但不会缩短锁持有时间,反而可能堆积更多等待 - 确认没有应用层逻辑在事务中跨引擎操作,或长时间持有
LOCK TABLES
最彻底的解法仍是迁移至 InnoDB——concurrent_insert 是止痛药,不是手术刀。


















