执行计划进阶:读懂filtered和rows的组合,精准判断索引设计质量

简介: EXPLAIN执行计划中,rows和filtered是两个最容易被低估的字段。单独看rows,不知道索引筛选得干不干净;单独看filtered,不知道绝对数量有多大。只有把两者组合起来,才能真正判断索引设计质量。本文从rows和filtered的定义出发,拆解三种典型组合场景的诊断逻辑,并通过真实案例演示如何用这两个字段精准评估索引选择性、回表代价和优化空间,帮助读者从“会看EXPLAIN”升级到“会用EXPLAIN做诊断”。

大家好,我是小耶,写功课只是为了我踩过的坑,你们别再踩了!

用EXPLAIN看执行计划,大多数人只看三样东西:type是不是ALL、key是不是NULL、Extra有没有Using filesort。但如果只看到这个程度,你离“真正读懂执行计划”还有一段距离。

真正该看的,是rows和filtered的组合。

单独看rows,你只知道“要扫多少行”,但不知道索引筛得干不干净。单独看filtered,你只知道“过滤比例”,但不知道绝对数量有多大。只有把两者放在一起看,才能判断索引设计到底行不行。今天把rows和filtered的组合逻辑彻底拆开讲一遍。

一、rows和filtered分别是什么?

rows:优化器估算的、需要扫描的行数。它是一个相对值,不是精确值,但量级决定了查询成本的基数。

filtered:存储引擎返回的行中,满足剩余WHERE条件的比例。比如rows=1000、filtered=10%,表示存储引擎返回了1000行,经过WHERE条件过滤后最终只留下100行。filtered=100%表示索引精准定位,无需额外过滤;filtered越低,说明索引筛掉的“垃圾”越少,回表后还要过滤掉大量数据。

关键认知:rows是“扫描量”,filtered是“过滤效率”。两者相乘(rows × filtered%)就是你最终需要返回的行数,但更重要的是——filtered越低,意味着索引帮上忙的就越少。

二、三种典型组合及其诊断结论

组合一:rows小、filtered高(✅ 索引设计优秀)

rows=100,filtered=100%。优化器估算扫描100行,全部命中,不需要额外过滤。

诊断结论:索引精准定位了数据,回表代价极小。说明索引列选择性和顺序都很好。

组合二:rows小、filtered低(⚠️ 索引用了,但没完全用)

rows=100,filtered=10%。优化器估算扫描100行,但最终只留下10行,90%的行在回表后被过滤掉。

诊断结论:索引只帮你定位到了一小部分数据,但WHERE条件中还有重要字段不在索引里,导致回表后大量过滤。说明索引设计“缺了东西”——可以把被过滤的字段加进索引,或调整索引列顺序。

组合三:rows大、filtered高(⚠️ 索引命中精准,但扫描范围太大)

rows=100万,filtered=100%。优化器估算扫描100万行,全部命中。

诊断结论:索引确实帮你精准定位了,但问题在于——你要查的数据本身就有一百万行。这说明索引选择正确,但查询条件本身过滤性太差(比如查“2026年全年订单”),或者数据量本身就大。这时候优化方向不是改索引,而是考虑分区表、物化视图或业务层面缩小查询范围。

组合四:rows大、filtered低(❌ 索引设计有问题,最差组合)

rows=100万,filtered=5%。扫描100万行,最终只留5万行。

诊断结论:索引几乎没起什么作用——扫描了大量数据,回表后又过滤掉95%。这是最需要优化的组合。大概率是索引列选择性极差(比如status只有两三个值),或者索引顺序完全不对。优先考虑重建索引或重新设计查询条件。

三、真实案例:从rows和filtered组合定位问题

一个订单表有500万行数据,status字段只有三个值(PAID/UNPAID/REFUND),索引为(status)。业务SQL:

sql

SELECT * FROM orders WHERE status = 'PAID' AND create_time > '2026-01-01';

EXPLAIN输出:

type key rows filtered Extra
ref idx_status 150万 30% Using where

诊断:rows=150万(status='PAID'占了约30%的数据),filtered=30%(还要再过滤create_time)。组合来看,索引只筛掉了70%的数据,回表后还要再过滤70%,实际有效数据只有45万行。扫描150万行、回表150万次,只为了拿45万行数据——浪费巨大。

优化:改成复合索引(status, create_time)。新EXPLAIN:

type key rows filtered Extra
ref idx_status_ctime 45万 100% Using index condition

效果:rows从150万降到45万,filtered从30%升到100%,查询时间从4.2秒降到0.3秒。

四、在多表JOIN中,filtered决定了驱动顺序

很多人不知道,filtered在JOIN中还有一个关键作用——它直接影响优化器选择哪个表作为驱动表。

优化器在选择JOIN顺序时,会估算“驱动表行数 × filtered”作为被驱动表的匹配次数。比如:

  • 表A:rows=10000,filtered=50% → 估算匹配5000次
  • 表B:rows=5000,filtered=90% → 估算匹配4500次

优化器可能会选择表B作为驱动表,即使它的rows更小——因为filtered更高意味着更少的无效匹配。这就是为什么有时候你加了个索引,JOIN顺序突然变了——filtered变了,优化器的估算变了。

诊断建议:如果你发现JOIN顺序不合理,检查被驱动表的连接字段是否有索引,以及filtered是否偏低。

五、总结

EXPLAIN的rows和filtered,单独看都没什么用,组合起来才是诊断索引设计质量的关键工具:

rows filtered 诊断 方向
小 高 ✅ 优秀 保持
小 低 ⚠️ 索引缺字段 加入被过滤的列
大 高 ⚠️ 数据量本身大 分区/物化视图/缩小范围
大 低 ❌ 索引设计问题 重建索引或改写SQL

下次用EXPLAIN的时候,别只看type和key。把rows和filtered两个数字摆在一起,问问自己:这个组合告诉我什么?回答这个问题,你就能从“会看EXPLAIN”升级到“会用EXPLAIN做诊断”。

小耶在手,SQL 不愁

还有什么想了解的,欢迎留言!小耶一定知无不言言无不尽……我们下次见~

相关文章
|
5月前
|
人工智能 Cloud Native 关系型数据库
MySQL 8.4 LTS来了!从8.0到8.4,DBA必须知道的5个核心变化
MySQL 8.0社区版将于2026年结束生命周期,8.4 LTS作为首个长期支持版本,提供5年超长支持周期(至2031年)。本文从InnoDB并行查询、Redo Log动态容量、默认认证插件变更、参数默认值调整、云原生适配五个维度,梳理DBA升级前必须掌握的核心变化,并提供升级检查清单。
|
5月前
|
SQL 人工智能 自然语言处理
Vibe Coding 是什么?当“感觉编程”遇上数据库
Vibe Coding是2026年编程圈最火的概念之一,指开发者通过自然语言描述“感觉”或“意图”,由AI自动生成代码、调试、优化。本文从Vibe Coding的起源讲起,分析它如何改变数据库开发方式:从手写SQL到自然语言查询、从人工调索引到AI推荐、从经验运维到智能诊断。探讨这项趋势对DBA职业的影响,并给出拥抱变化的实用建议。技术会变,但人的判断力、审美和业务理解才是长期竞争力。
|
3月前
|
存储 消息中间件 SQL
Redis大Key优化完全指南:三种类型、五种拆分策略、一套渐进式方案
大key是Redis最隐蔽的性能杀手——它不会直接报错,只会让你半夜收到延迟告警、主从断开、请求超时。本文从大key的三种类型出发,拆解String、Hash、Set、ZSet、List五类数据结构的拆分策略,提供渐进式拆分的完整方案,并给出数据结构选型的“防患于未然”建议,帮助读者从“发现大key”走向“根治大key”。
|
3月前
|
SQL 关系型数据库 MySQL
全量迁移时源库还在写,数据一致性怎么保证?
数据库迁移最怕的不是慢,是“搬完了发现数据不对”。全量迁移时源库还在写、增量同步时顺序乱了、异构数据库类型映射丢了精度——这些坑,在POC阶段很难暴露,一上生产就变成事故。本文从三种一致性风险场景出发,拆解全量校验、增量校验、抽样校验的完整方法论,帮助读者在迁移项目中做到“数据搬得对、心里有底”。
|
4月前
|
存储 传感器 监控
时序数据是什么?2026年企业为什么离不开时序数据库
时序数据是2026年增长最快的数据类型之一。据行业预测,工业物联网产生的时序数据量将占企业总数据量的75%以上,年复合增长率超过40%。时序数据已从“技术补充”升级为“核心资产”。本文从时序数据的基本概念出发,讲解时序数据的特征、应用场景,以及为什么传统数据库处理不了时序数据,帮助读者建立对时序数据的完整认知。
|
3月前
|
存储 架构师 数据库
从DBA到数据架构师:技术债务管理是分水岭
“架构债”在业务快速迭代中被不断放大,最终成为系统稳定性的定时炸弹。本文从数据架构的视角出发,拆解数据库技术债务的四种典型类型,提供识别、评估和偿还的完整方法论,帮助读者从“数据库管理员”升级为“数据架构师”。
|
3月前
|
SQL 缓存 NoSQL
Redis缓存三大坑:穿透、击穿、雪崩,一次讲透
缓存穿透、击穿、雪崩,名字像兄弟但成因解法完全不同。本文深入讲解三种问题的原理、实现细节与隐藏的坑,覆盖布隆过滤器、互斥锁、逻辑过期、过期随机化等解法。
|
3月前
|
SQL 监控 关系型数据库
从库延迟排查实战:主从同步慢了,业务方比你先知道
主从延迟是DBA最头疼的问题之一,因为业务方永远比你先知道——刚下单的订单在查询页消失了、刚提交的表单在报表里找不到。但当你打开监控,Seconds_Behind_Master可能还是0。本文从主从延迟的三种本质成因出发,拆解大事务阻塞、并行复制瓶颈、从库负载干扰三大核心场景,提供一套从现象到根因的完整排查路径,帮助读者在业务方投诉之前就把问题摁住。
|
3月前
|
SQL JSON 移动开发
SQL派生表优化实战:从物化机制到LATERAL JOIN的完整进阶
很多人只知道“子查询改JOIN就快了”,但不知道为什么,也不知道什么时候该改、什么时候不该改。本文从派生表的物化机制出发,拆解临时表膨胀、索引失效的根因,通过真实案例对比派生表、CTE、LATERAL JOIN三种写法的性能差异,帮助读者从“知道现象”升级到“理解原理”。
|
3月前
|
存储 固态存储 关系型数据库
从月账单5万到3.5万:云数据库成本优化的完整复盘
上云本应是降本增效,但很多企业上云之后,账单反而越滚越大。实例规格买高了、历史数据堆在SSD上、测试环境没人关、过期快照没清理——每一笔费用都在悄悄累积。本文从云账单的三大“黑洞”出发,拆解云成本失控的根因,给出实例降配、冷热数据分层、僵尸资源清理三条可落地的优化路径,帮助DBA和运维工程师用数据驱动成本优化,让每一分钱都花在刀刃上。