Key_blocks_used比命中率更关键,因其反映索引缓冲实际使用量:若长期仅20~50或持续为0,说明缓存未有效填充,存在索引损坏、备份不一致等风险;盲目调大key_buffer_size可能无效甚至有害。

Key_blocks_used 为什么比命中率更关键
只看 Key_reads / Key_read_requests 这个比值容易误判缓存是否真在干活。比如 Key_read_requests 是千万级,Key_reads 才几十次,算出来命中率 99.99%,但若 Key_blocks_used 长期只有 20~50,说明缓存压根没被填满——索引访问太分散,或者查询根本没走索引。
真正该盯住的是 Key_blocks_used 的绝对值和趋势:
-
Key_blocks_used持续 - 对比
key_buffer_size能容纳的总块数(key_buffer_size / 1024,单位是 KB 块),若实际使用块远低于理论容量,说明访问集中度低或 SQL 未命中索引 - 如果
Key_blocks_used接近Key_blocks_unused,不是“满了”,而是碎片化严重:大量 1KB 小空闲块无法合并,有效缓存率反而下降
每秒 Key_reads 才是性能瓶颈信号
Key_reads 是累计值,单看一个快照毫无意义。真正拖慢查询的,是每秒从磁盘读取索引页的次数。
实操建议用持续采样法抓真实速率:
- 执行
mysqladmin ext -ri10 | grep Key_reads,跳过第一行(启动累计值) - 取后续每 10 秒增量,除以 10 得到每秒速率
- HDD 环境超过
15/s、SSD 超过50/s就得干预 - 若速率稳定爬升,优先查
Handler_read_rnd_next:它飙升说明大量索引请求最终 fallback 到全表扫描,不是缓存小,是 SQL 写法或索引设计有问题
Key_blocks_not_flushed 暴露延迟写风险
Key_blocks_not_flushed 表示已修改但尚未刷盘的脏块数。它缓慢上涨,是 delay_key_write 开启但磁盘 I/O 跟不上的典型表现。
这个值长期 > 0 会带来两个隐患:
- 意外中断(如 kill -9 或断电)后,
.MYI文件可能损坏,表无法打开 - 备份时若直接拷贝
.MYI文件,大概率拿到不一致的索引状态 - 执行
FLUSH TABLES可清零该值,但必须避开业务高峰;更稳妥的是先FLUSH TABLES WITH READ LOCK,再拷贝
别盲目调大 key_buffer_size 的三个理由
调大 key_buffer_size 不等于性能提升,尤其在以下情况:
- 32 位系统硬上限是
2G,64 位也建议不超过4G;超限后部分 MySQL 版本(如 5.7 早期)会静默截断,不报错也不警告 - 实际索引总大小远小于配置值:用
SELECT CEILING(SUM(INDEX_LENGTH) * 1.1 / 1024 / 1024) AS `mb_needed` FROM information_schema.TABLES WHERE ENGINE = 'MyISAM'算出真实需求,设成 2G 却只有 300MB 索引,纯属浪费 -
Key_reads / Key_read_requests已稳定 99.9%),再加内存无收益;此时应转向优化慢查询或迁移到 InnoDB
最常被忽略的一点:MyISAM 表混用大量 TEXT/BLOB 字段时,INDEX_LENGTH 统计依然准确,但数据文件膨胀会导致缓存策略失效——这时光看 Key_% 状态不够,得结合 EXPLAIN 和 Handler_read_* 系列指标交叉验证。


















