跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

如何利用查询执行统计来对比不同索引的效率_相同SQL执行耗时对比

EXPLAIN ANALYZE 耗时不准因受缓存、锁和系统负载干扰,应取后两次 Execution Time 平均值,并关注 Buffers(PG)或 Handler_read_*(MySQL)等真实 I/O 指标,而非单次耗时。 查
EXPLAIN ANALYZE
时为什么耗时不准 因为单次执行受缓存、锁、系统负载干扰太大,直接看
execution time
容易误判索引优劣。真正要对比的是「稳定状态下的执行路径和资源消耗」,不是某一次快慢。 务必在相同数据量、相同连接会话、关闭查询缓存(
SET SESSION query_cache_type = OFF
)下测试 首次执行会触发磁盘读和 buffer pool 加载,至少执行 3 次,取后两次的
Execution Time
平均值
EXPLAIN ANALYZE
输出里的
Buffers
行(PostgreSQL)或
Handler_read_*
状态(MySQL)比耗时更反映索引实际效率 MySQL 下怎么让
EXPLAIN
显示真实 I/O 开销 默认
EXPLAIN
不显示磁盘读,得靠
SHOW STATUS LIKE 'Handler_%'
配合清零再执行 SQL,才能看到索引实际扫了多少行、回表几次。 执行前先运行
FLUSH STATUS
,再跑目标 SQL 立刻查
SHOW STATUS LIKE 'Handler_read%'
:重点关注
Handler_read_next
(索引扫描行数)、
Handler_read_rnd
(回表次数),越小越好 如果
Handler_read_rnd
远高于
Handler_read_next
,说明索引没覆盖查询字段,正在大量随机 IO 回表 PostgreSQL 中
EXPLAIN (ANALYZE, BUFFERS)
关键看哪几行 重点不是最上面的总耗时,而是每层节点的
Buffers: shared hit=xxx read=yyy
和
Rows Removed by Filter
。
shared read=
是真磁盘读,>0 就说明索引或表没被缓存住;反复测试时这个值应趋近于 0 才算稳定 如果某层出现
Rows Removed by Filter: 9990/10000
,说明索引选型错误——它扫了 1 万行,只留下 10 行,过滤成本远高于索引收益 注意
Index Scan using idx_a_b on t
后面有没有
Index Cond: (a = $1)
和
Filter: (b > $2)
并存:后者意味着 b 字段没被索引有效利用 SQL 相同但执行计划突变?检查这三处隐性干扰 看起来是同一句 SQL,但执行计划可能因隐式类型转换、统计信息过期、绑定变量窥探而完全不同,导致索引对比失效。 用
SELECT pg_typeof(col)
确认 WHERE 条件中字段和参数类型严格一致,避免
WHERE id = '123'
触发隐式转 cast 导致索引失效 执行
ANALYZE table_name
(PostgreSQL)或
ANALYZE TABLE table_name
(MySQL),确保优化器基于最新数据分布做决策 MySQL 中如果用了预处理语句,第一次执行的执行计划会被复用,加
/*+ RECOMPILE */
或改用普通语句重试 实际对比时,最常被忽略的是「索引是否真正减少了物理读」,而不是「执行时间少了多少毫秒」。磁盘 IO 波动大,buffer hit rate 和 filter 效率才是跨环境可复现的判断依据。

相关文章