Handler_read_key表示执行器成功通过索引定位起点的次数(如WHERE a=1走索引查找),Handler_read_next表示后续调用ha_index_next()向后遍历索引项的次数(常见于范围查询或ORDER BY扫描),二者高仅说明索引路径深、遍历多,并非直接等价于慢查询或磁盘IO。

直接看 SHOW STATUS LIKE 'Handler_%' 就能拿到各 handler 接口被调用的累计次数,但要注意:这些数字不是“磁盘IO次数”,也不是“慢查询指标”,只是执行器向存储引擎发起的读取动作计数。
Handler_read_key 和 Handler_read_next 到底代表什么
Handler_read_key 是执行器调用 ha_index_read() 成功定位到索引起点的次数,比如 WHERE a = 1 走了索引查找;Handler_read_next 是后续反复调用 ha_index_next() 向后遍历索引项的次数,常见于范围查询或 ORDER BY 复用索引扫描。
- 这两个值高 ≠ 慢,只说明索引路径走得深、遍历多
- 如果
Handler_read_next远高于Handler_read_key(比如 1000:1),大概率是优化器选了窄索引做范围扫描,但没覆盖SELECT字段,导致回表压力大 - InnoDB 的
ha_index_next()在内存页内跳指针,不必然触发磁盘读;哪怕 Buffer Pool 命中率 100%,它也会涨
Handler_read_rnd_next 高就一定有问题吗
Handler_read_rnd_next 统计的是执行器调用 ha_rnd_next() 的次数,对应全表扫描或回表后的随机行读取。它常被误读为“正在扫磁盘”,其实完全不是。
- 这个调用可能读的是刚从磁盘载入的页,也可能是 Buffer Pool 里缓存了半年的老页
- 真正反映物理读的是
Innodb_buffer_pool_reads,不是这个值 - 若你加了
FORCE INDEX后Handler_read_rnd_next仍很高,说明索引没覆盖SELECT列,必须回聚簇索引——这时该看执行计划里有没有 “Using where; Using index”
如何对比两条 SQL 的 handler 行为差异
别只看单次查询后的全局状态,要抓会话级快照再做减法:
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
FLUSH STATUS; SELECT * FROM orders WHERE user_id = 123 AND status = 'paid' ORDER BY created_at DESC LIMIT 10; SHOW STATUS LIKE 'Handler_%';
重点比对这几组关系:
-
Handler_read_first + Handler_read_next ≈ 10?接近说明走了覆盖索引+有序扫描,理想路径 -
Handler_read_rnd_next > 10?说明每行都要回表,且回表后还做了额外跳转(比如排序字段不在索引里) -
Handler_read_key == 0但Handler_read_rnd_next > 0?基本确认走的是全表扫描,没命中任何索引
为什么有时候断点打在 ha_index_read() 却不命中
因为执行器调用的是基类 handler::index_read(),实际执行的是 InnoDB 注册的虚函数 ha_innobase::index_read()。调试时断点要打在子类实现上,否则永远进不去。
- 更隐蔽的情况是:优化器判定能用覆盖索引,直接从 B+ 树页内拷贝字段(
key_copy()),根本不会走到ha_index_read() - 此时
EXPLAIN显示 “Using index”,但所有Handler_read_*都几乎不涨——这不是 bug,是优化生效 - 想强制触发 handler 调用?加个非索引字段到
SELECT里,比如SELECT *, updated_at FROM ...
Handler 指标本质是执行器和引擎之间的一层“接口调用日志”,它不告诉你数据在哪,也不告诉你慢在哪,只告诉你“上层请求引擎干了哪些事”。真正定位 IO 瓶颈得结合 Innodb_buffer_pool_reads 和 performance_schema.events_waits_history_long 里的 wait/io/file/innodb/innodb_data_file 事件。

















