myisam写入并发低的根本原因是表级锁和无事务机制;优化需绕开缺陷:设concurrent_insert=2、剥离select查询、禁用insert delayed、精简字段与索引。

MyISAM 写入并发低,根本原因不是配置没调对,而是它天生不支持真正的并发写入——表级锁 + 无事务机制决定了它在混合读写或高写入场景下必然卡顿。优化方向必须围绕“绕开它的缺陷”,而不是强行让它变快。
concurrent_insert=2 必须设,但只对尾部追加有效
MyISAM 的并发插入仅在数据文件末尾追加时生效,concurrent_insert=2 是唯一推荐值,它强制允许即使表里有空洞(删除后留下的碎片)也继续往结尾并发写入。
- 必须在
my.cnf中显式写入:concurrent_insert = 2,然后重启 MySQL(/etc/init.d/mysqld restart),SET GLOBAL动态设置无效 - 该配置对
INSERT有效,但对REPLACE、DELETE、UPDATE无效;一旦执行了这些操作,MyISAM 可能重建数据文件,后续并发插入会暂时失效 - 如果业务中存在定期
OPTIMIZE TABLE,注意它会重排数据、清空空洞,反而让concurrent_insert=2的效果更稳定;但频繁执行会阻塞写入,建议夜间低峰期运行
日志表必须剥离 SELECT 查询
MyISAM 表级锁意味着:哪怕一个 SELECT COUNT(*) 正在执行,所有 INSERT 都得排队等待。日志类表若混杂统计、监控拉取等读操作,吞吐量会断崖下跌。
- 禁止在日志表上做任何
SELECT——包括应用层的COUNT、MAX(id)、GROUP BY等聚合查询 - 把读需求迁移到单独的汇总表(如按小时/天预聚合)、外部存储(Elasticsearch)、或物化视图(用触发器+汇总表模拟)
- 如果必须查原始日志,改用
SELECT ... INTO OUTFILE导出后离线分析,避免走 SQL 查询路径
别再试 INSERT DELAYED,它已彻底消失
MySQL 5.6 起完全移除 INSERT DELAYED 语法,任何尝试都会报错 ERROR 1064 (42000)。它过去只适用于 MyISAM,且延迟不可控、数据丢失风险高,现在连语法解析都失败。
- 不要查旧文档、不要降级 MySQL、不要在应用代码里保留该语句逻辑
- 替代方案只有两个:批量插入(
INSERT INTO t VALUES (),(),()...)或引入消息队列(Kafka / RabbitMQ)缓冲写请求,由消费者攒批刷入 - 每批控制在 100–500 行,避免超
max_allowed_packet;应用层无法合并时,队列是更可控的选择
字段与索引越精简越好
MyISAM 日志表的写入瓶颈,80% 来自 I/O 和锁等待,而非 CPU 或内存。字段冗余和索引过多直接放大每次写入的磁盘压力。
- 字段类型最小化:
TINYINT代替INT,VARCHAR(32)代替TEXT,时间用INT UNSIGNED存 Unix 时间戳(比DATETIME少 3 字节) - 索引只保留必要项:日志通常按时间范围查询,建一个
created_at索引足矣;禁用UNIQUE约束,它会让每次插入额外校验唯一性,拖慢写入 - 避免
NULL字段,MyISAM 对NULL的处理开销比非空字段高;默认值尽量设为 0 或空字符串,而非NULL
真正卡住 MyISAM 日志写入的,从来不是 concurrent_insert 设没设对,而是有没有 SELECT 在旁边盯着、单次插入的数据包是不是太大、字段和索引是不是还在堆砌“以防万一”。这三个点不动,调参毫无意义。











