执行计划进阶:读懂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 不愁

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

相关文章
|
2月前
|
人工智能 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升级前必须掌握的核心变化,并提供升级检查清单。
|
2月前
|
SQL 人工智能 自然语言处理
Vibe Coding 是什么?当“感觉编程”遇上数据库
Vibe Coding是2026年编程圈最火的概念之一,指开发者通过自然语言描述“感觉”或“意图”,由AI自动生成代码、调试、优化。本文从Vibe Coding的起源讲起,分析它如何改变数据库开发方式:从手写SQL到自然语言查询、从人工调索引到AI推荐、从经验运维到智能诊断。探讨这项趋势对DBA职业的影响,并给出拥抱变化的实用建议。技术会变,但人的判断力、审美和业务理解才是长期竞争力。
|
3月前
|
关系型数据库 MySQL 测试技术
JOIN、IN、EXISTS谁最快?实测三种写法性能差异与执行计划深度剖析
本文用MySQL 8.0实测拆解`IN`/`EXISTS`/`JOIN`子查询性能:从执行计划、半连接优化、临时表开销等底层原理出发,结合10万+100万数据实测(`EXISTS`最快95ms),给出三条选型铁律——告别盲从“最佳实践”,只选最适配业务与数据的写法!
|
26天前
|
存储 人工智能 关系型数据库
湖库一体:2026年数据库架构的“终极答案”还是新瓶装旧酒?
2026年6月,OceanBase发布湖库一体AI数据库,阿里云PolarDB年初已推出AI数据湖库(Lakebase),Databricks也在6月推出了LTAP架构。“湖库一体”成为2026年数据库圈最热的概念之一。本文从湖库一体的概念定义出发,拆解其技术原理,对比“湖仓一体”与“湖库一体”的差异,分析三大厂商的落地路径,并讨论这一趋势对DBA和架构师的现实意义。
|
2月前
|
SQL 运维 自然语言处理
国产向量数据库有哪些?两大技术流派深度对比与选型指南
向量数据库是2026年数据库领域增长最快的细分赛道之一。本文从RAG应用和企业知识库的实际需求出发,系统梳理国产向量数据库的两大技术流派——独立向量数据库与融合型向量数据库,深入对比两者的架构差异、适用边界和选型逻辑。
|
21天前
|
关系型数据库 MySQL 数据库
字符集没统一,DBA的头发就是这么掉光的
本文讲解数据库字符集(UTF8/GBK/Latin1)和排序规则(collation)的底层原理,分析数据迁移乱码、JOIN因collation不同走不了索引、emoji存储失败等常见问题的根因,给出字符集选型建议和排查方法。
|
21天前
|
供应链 安全 前端开发
24 小时三类加密货币攻击全链路技术解析与闭环防御研究
本文以2026年三起真实加密攻击事件为样本,系统剖析移动端仿冒APP钓鱼、Solana钱包私钥窃取、npm供应链投毒的技术链路,还原恶意代码,提出芦笛分层风险评分模型,并构建覆盖开发、终端、链上的三维闭环防御体系,助力Web3安全实战防护。(239字)
105 0
|
21天前
|
SQL Oracle 关系型数据库
Oracle AWR性能调优实战:从等待事件定位到执行计划优化的全流程指南
通过AWR报告的Load Profile、Top 5 Timed Events定位全表扫描根因,结合执行计划分析基数估算偏差,补充统计信息与复合索引,并将业务代码单次COMMIT改为批量提交,将核心报表从45分钟优化至5分半。
|
20天前
|
SQL JavaScript 关系型数据库
递归CTE实战:用SQL搞定树形结构查询,告别“写死”代码
组织架构、商品分类、菜单权限、BOM清单——树形结构查询是日常开发中高频出现的需求。很多开发者的做法是“写死层级”或“循环查库”,代码又臭又长,性能还差。递归CTE是解决这类问题的标准写法,但很多人一看到WITH RECURSIVE就觉得头大。本文从三个真实场景出发,手把手教读者写出能直接用的递归CTE,并讲清楚执行机制和性能陷阱。
|
15天前
|
SQL 关系型数据库 MySQL
批量DML的性能与一致性:不是所有“批量操作”都应该用批量SQL
批量操作是日常开发中提升性能的常用手段,但“批量”不等于“越快越好”。批量大小不当、事务边界不清、缺乏错误处理,都可能让批量操作从“性能优化”变成“性能灾难”。本文从批量DML的执行机制出发,讲解批量大小对性能的影响曲线、事务边界的设计原则、批量操作中的数据一致性保障,以及如何根据业务场景选择合理的批量策略,帮助读者写出既快又稳的批量操作代码。