show status like 'key\_%' 缓存命中率暴跌主因是key_buffer_size不足或被挤出导致逻辑失效,而非索引本身失效;myisam索引全依赖该全局缓冲池,内存不足、并发刷脏页等均会推高key_reads。

为什么 SHOW STATUS LIKE 'Key_%' 显示缓存命中率突然暴跌
不是索引本身失效,而是 key_buffer_size 分配不足或被挤出导致的「逻辑失效」。MyISAM 表的索引页全靠这个全局缓冲池缓存,一旦物理内存不足、其他进程吃掉内存、或并发查询频繁刷脏页,Key_reads 就会飙升,Key_read_requests 却没变——说明请求没少,但缓存不顶用了。
实操建议:
- 先看
Key_reads / Key_read_requests比值,持续 > 0.01 就得警惕;低于 0.001 才算健康 - 检查
key_buffer_size是否远小于所有 MyISAM 索引文件总大小(用ls -l *.MYI算) - 确认没混用
query_cache_type=1——它和 key buffer 争内存,且 MySQL 5.7+ 已移除,旧配置残留会干扰判断 - 临时加内存?别直接调大:超过 2GB 在 32 位系统可能崩溃,Linux 下还要看
/proc/sys/vm/swappiness,值太高会导致 buffer 被 swap 出去
MyISAM 索引缓存和 InnoDB 的 innodb_buffer_pool_size 能一起调吗
能,但必须分开看——它们压根不共享内存,也不互相感知。MyISAM 用 key_buffer_size,InnoDB 用 innodb_buffer_pool_size,两者加起来不能超物理内存,否则 OOM killer 可能干掉 mysqld 进程。
常见错误现象:
- 只调大
innodb_buffer_pool_size,忘了 MyISAM 表还在跑,结果Key_reads暴涨,慢查询日志里全是SELECT ... WHERE indexed_col = ? - 在混合引擎库中把
key_buffer_size设成 0,MyISAM 索引全走磁盘,但错误日志里不报错,只默默变慢
使用场景提醒:
- 纯 InnoDB 库?把
key_buffer_size设成 8M~16M 足够(仅用于系统表如mysql.host) - 仍有大量 MyISAM 表(比如老 CMS 或日志归档表),
key_buffer_size建议设为「所有 .MYI 文件大小总和 × 1.2」,但上限别超 4GB(32 位系统限制) - 调整后必须重启 MySQL——
SET GLOBAL对这两个变量无效
Key_blocks_used 一直接近 Key_blocks_unused 是不是缓存满了
不是满,是「碎片化严重」。MyISAM 缓冲池按 1KB 块管理,频繁增删索引页会导致大量小空闲块无法合并,Key_blocks_used 高但实际有效缓存率低。
判断依据:
- 查
Key_blocks_unused很小,但Key_blocks_used也上不去(比如才几百),说明分配了空间却没真正用起来 -
Key_blocks_not_flushed > 0且持续增长,说明脏块积压,flush 线程跟不上,可能因磁盘 I/O 瓶颈或delay_key_write开着但没配好
实操动作:
- 运行
FLUSH TABLES强制刷脏页并重置缓存块状态(注意:会锁表,选低峰期) - 确认
delay_key_write是 ON 还是 OFF:ON 时写索引不落盘,靠 flush 保证一致性;OFF 时每次 update 都写,压力大但安全 - 长期方案:把关键 MyISAM 表转成 InnoDB(
ALTER TABLE t ENGINE=InnoDB),避免 key buffer 碎片问题
为什么加了内存、调了参数,Key_read_requests 还在涨
因为这不是缓存问题,是查询本身没走索引。缓存再大,查不到索引页也没用。Key_read_requests 统计的是「尝试读索引页」的次数,哪怕 WHERE 条件没命中任何索引,MySQL 也会去 key buffer 里找——找不到就回磁盘,但请求已计入。
排查重点:
- 开
slow_query_log+log_queries_not_using_indexes=ON,抓出那些全表扫描的 SQL - 对高频慢查执行
EXPLAIN,重点看type是ALL还是index,key列是否为NULL - 注意隐式类型转换:
WHERE varchar_col = 123会让索引失效,日志里看不到警告,但Key_read_requests照涨 - MyISAM 不支持索引下推(ICP),
WHERE a = ? AND b > ?如果只有(a)单列索引,b条件仍需回表过滤,也会触发额外索引读
最常被忽略的一点:缓存调优永远排在索引设计之后。没合适的索引,再多内存也只是给磁盘 I/O 做缓冲垫。











