myisam在只读报表中快,因其砍掉事务、mvcc、行锁、崩溃恢复和聚簇索引,仅保留顺序存储的.myd文件与直接物理偏移定位;但一旦有写入即性能崩塌,且依赖定期analyze table、合理key_buffer_size及关闭查询缓存等严格运维前提。

MyISAM 在只读报表业务中“快”,不是因为它更先进,而是它把所有写保障机制全砍掉了——事务、MVCC、行锁、崩溃恢复、聚簇索引结构统统不要,只留最简路径读数据。一旦有写入(哪怕一次 INSERT 或 UPDATE),这个“快”立刻崩塌。
MyISAM 的 .MYD 文件为什么顺序读得快
MyISAM 把记录按插入顺序堆在 .MYD 文件里,没页头、没事务ID、没回滚指针、没隐藏列。全表扫描时,磁盘读是连续的,OS 预读能高效命中;SELECT * FROM t LIMIT 1000 这种操作不用走 B+ 树,直接按偏移跳转就行。
- 前提是表用的是
FIXED行格式(所有字段定长);含VARCHAR或TEXT会退化为DYNAMIC,碎片多了就变随机 I/O -
ANALYZE TABLE必须定期跑,否则统计信息不准,优化器可能选错执行路径 - 并发高时,
.MYI文件头(存行数、索引统计)会成为文件系统热点,table_open_cache至少设到4096
key_buffer_size 是 MyISAM 读性能的实际瓶颈
MyISAM 的索引全部加载进全局 key_buffer_size,不像 InnoDB 按需加载页。这个值设小了,Key_reads 暴涨;设大了,挤占 OS 缓存,.MYD 读反而变慢。
- 默认
8MB对生产环境基本无效,建议从256MB起调,上限别超物理内存的 25% - 必须配
myisam_stats_method = NULLS_UNEQUAL,否则NULL值会让索引统计失真 -
query_cache_type必须关(MySQL 5.7+ 默认关,但旧配置常开着——一次写就让整表缓存失效)
MyISAM 的 COUNT(*) 为什么秒出,但别信它
SELECT COUNT(*) FROM t 直接返回内存里的计数器值,不碰 .MYD。但这计数器只在 INSERT/DELETE 时由表级锁保护更新,一断电或手工改文件就失效。
-
SELECT COUNT(*) WHERE status=1还是要扫数据,不享受这个优化 - 用
myisamchk --analyze或ANALYZE TABLE才能重同步计数器 - 高并发写场景下,计数器更新本身会成锁争用点,QPS 上不去
READ_CONCURRENT 看似支持并发读写,实际几乎没用
它只允许一个无冲突的 INSERT 追加到表末尾,同时不阻塞已有 SELECT。但前提苛刻:
- 建表时必须显式声明
DELAY_KEY_WRITE = 1 -
INSERT不能带WHERE、不能触发主键/唯一键冲突、表不能有FULLTEXT索引 -
UPDATE和DELETE仍触发全表锁,SHOW PROCESSLIST出现Waiting for table level lock就说明卡死了
真正容易被忽略的是:MyISAM 的“快”建立在数据完全静态、查询极简单、运维接受“坏了就重导”的前提上——而这类场景,早该用 Redis 或本地缓存扛了,而不是靠引擎取巧。











