索引命中率直接反映了MySQL利用索引的效率。命中率过低意味着大量查询在做全表扫描,或者频繁从磁盘读取索引页,数据库的整体吞吐会明显下降。分析索引命中率一般从两个维度入手:一是服务器层面的索引缓冲区命中率,二是单条SQL语句是否真正用上了索引。这两个层面的排查手段不同,下面分别详细说明。

一、通过 SHOW STATUS 计算索引缓冲区命中率
MySQL提供了丰富的状态变量,其中与索引读取相关的几个指标是分析命中率的基础。执行以下语句可以查看当前的累计统计值:
SHOW GLOBAL STATUS LIKE 'Key%';
输出结果中重点关注四个变量:Key_read_requests表示从索引缓冲区(key buffer)中读取索引块的请求次数,Key_reads表示缓冲区中没有命中、不得不从磁盘物理读取的次数。同理,Key_write_requests和Key_writes对应写入侧的统计。
索引缓冲区命中率的计算公式为:1 - Key_reads / Key_read_requests。一般来说,这个值在99%以上说明缓冲区大小合适;如果低于95%,通常意味着key_buffer_size设置过小,或者索引数据量已经远超缓冲区容量。可以用下面的SQL直接算出结果:
SELECT ROUND(
(1 - VARIABLE_VALUE / (SELECT VARIABLE_VALUE
FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Key_read_requests')) * 100, 2
) AS hit_rate_pct
FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Key_reads';
需要注意的是,Key_reads这套指标只对MyISAM引擎生效。InnoDB使用的是独立的缓冲池,对应的状态变量是Innodb_buffer_pool_read_requests和Innodb_buffer_pool_reads,计算方式完全相同。由于现在绝大多数表都是InnoDB,实际工作中更应该关注后者:
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';
此外,统计值是服务器启动以来的累计值,重启后会清零。如果想观察一段时间内的变化,可以借助performance_schema定时采样,或者使用监控工具持续采集。
二、用 EXPLAIN 判断单条SQL是否命中索引
服务器层面的命中率反映的是整体状况,而慢查询的根源往往在具体SQL上。分析单条SQL是否命中索引,最常用的工具就是EXPLAIN:
EXPLAIN SELECT order_no, amount FROM orders WHERE user_id = 10086 AND create_time > '2024-01-01';
查看执行计划时,重点看以下几个字段:type列如果是ref、range、const说明走了索引,如果是ALL则是全表扫描;key列显示实际使用的索引名,为NULL表示没有命中任何索引;rows列是预估扫描行数,行数越大说明索引过滤效果越差;Extra列中出现Using index代表覆盖索引,性能最佳。
除了EXPLAIN,MySQL还提供了更细粒度的分析手段。在SQL前加上EXPLAIN ANALYZE(MySQL 8.0.18以上支持),可以获取真实的执行统计,包括实际返回行数和耗时,比传统的估算值更准确。另外,optimizer_trace能输出优化器选择索引的完整决策过程,当你疑惑明明有索引却没被使用时,它可以告诉你代价估算的细节:
SET optimizer_trace = 'enabled=on'; SELECT * FROM orders WHERE user_id = 10086; SELECT * FROM information_schema.OPTIMIZER_TRACE;
常见的索引失效场景也值得逐一排查:对索引列使用函数或运算、隐式类型转换(如字符串列与数字比较)、前导模糊匹配LIKE '%xxx'、组合索引不满足最左前缀原则、OR连接了无索引的列等,都会导致优化器放弃索引。这些场景在慢查询日志中占比很高,是命中率下降的主要元凶。
三、利用 sys 和 performance_schema 做全局诊断
单条排查效率有限,MySQL 8.0自带的sys schema提供了不少汇总视图,可以快速定位没有使用索引的语句。最经典的一个视图是statements_with_full_table_scans,它直接列出执行过全表扫描的SQL及其执行次数:
SELECT query, exec_count, no_index_used_count, no_good_index_used_count FROM sys.statements_with_full_table_scans ORDER BY no_index_used_count DESC LIMIT 10;
另一个实用视图是schema_unused_indexes和schema_index_statistics。前者能找出从未被使用的索引,这些冗余索引不仅占用空间,还会拖慢写入速度,确认后可以删除;后者展示每个索引的读取行数和插入更新次数,帮助评估索引的实际价值。对于表级概览,schema_table_statistics_with_buffer包含逻辑读和物理读的统计,可以和缓冲池命中率对照分析。
统计信息过期也会导致索引选择异常。当表中数据大量增删后,innodb_stats_auto_recalc默认在约10%的行变更时才触发重算,中间可能存在统计偏差。必要时可以手动执行ANALYZE TABLE 表名刷新统计信息,让优化器基于准确的数据做决策。
综合来看,索引命中率的分析路径是:先用状态变量确认整体健康度,再用慢查询日志配合EXPLAIN定位问题SQL,最后通过sys视图做全局梳理。三者结合,才能既看到现象又找到根因,避免盲目加索引带来的负优化。
MySQL索引命中率索引优化慢查询优化修改时间:2026-09-08 10:10:53