filtered=100%表示服务器层未做额外行过滤,但不等于查询最优,需结合type、rows和key综合判断:若type为ALL且rows很大,仍是全表扫描;若type为ref且rows小,才说明索引高效。
Filtered = 100% 真的代表查询最优吗
不一定。filtered = 100% 只说明服务器层没做额外行过滤,但不等于查询快——它可能仍走 all 扫描、rows 高达百万,或 extra 里有 using filesort。关键要看它和 type、rows 的组合:
- 若
type是ref或eq_ref,且rows小(比如几十)、filtered= 100%,基本可判定索引高效、条件精准 - 若
type是ALL,rows= 500000,哪怕filtered= 100%,仍是全表扫描,性能瓶颈在 I/O -
filtered高但key为空,说明优化器根本没选索引,此时 100% 是“虚假繁荣”
Filtered 值低(比如 1%~10%)说明什么
表示存储引擎返回了大量数据,但服务器层只留下极小一部分,典型是“索引覆盖不全”。例如:
EXPLAIN SELECT * FROM order_info_14 WHERE purchaser_id = 123 AND order_status = 'completed';
如果只在 purchaser_id 上建了单列索引,执行计划中 key 会显示该索引,rows 可能是 100,但 filtered = 10%,意味着:引擎查出 100 行,其中仅 10 行满足 order_status = 'completed',其余 90 行白读了。
- 本质是
order_status列未被索引覆盖,导致回表后还要逐行判断 - 常见于联合索引字段顺序错位:比如建了
INDEX idx(a,b),却用WHERE b = ? AND a = ?,b无法走最左前缀 - 字符串类型比较时隐式转换(如
varchar字段与数字比较),也会让filtered骤降且key失效
如何让 Filtered 接近 100% 且真正有效
目标不是堆高 filtered 数值,而是让高 filtered 和低 rows、合适 type 同时出现。实操重点在索引设计:
- 把 WHERE 中高频等值条件字段放在联合索引最左侧,选择性高的放前面(比如
status区分度低,user_id区分度高,应建INDEX(user_id, status)而非反过来) - 确保查询中所有 WHERE 条件字段都落在同一索引内;若含范围查询(
>、BETWEEN),它右侧的字段无法用于索引过滤,filtered会断崖下跌 - 避免在索引字段上用函数:
WHERE DATE(create_time) = '2023-01-01'会让整个索引失效,filtered意义归零;改写为create_time >= '2023-01-01' AND create_time < '2023-01-02' - 用
EXPLAIN FORMAT=JSON查看filtered的估算依据,比传统格式多出condition_filtering_pct字段,可验证是否因统计信息过期导致误判
Navicat 里怎么看 filtered 并快速定位问题
Navicat 的“解释”结果表格默认不显示 filtered 列(尤其旧版本),需手动开启:
- 执行
EXPLAIN后,在结果表格右键 → “显示/隐藏列”,勾选filtered - 若仍不显示,说明当前 MySQL 版本低于 5.7(
filtered从 5.7 引入),此时只能靠rows和Extra推断过滤效率 - 对比
rows和实际返回行数:若rows= 1000 但结果只有 5 行,大概率存在低效过滤,filtered应远低于 100% - 注意 Navicat 自动补全的
SELECT *容易掩盖覆盖索引机会;测试时尽量写明所需字段,观察Extra是否出现Using index
filtered 是个信号灯,不是成绩单。它亮绿灯时得看路是不是真通;它变黄时,别急着调 SQL,先查索引定义和字段类型是否对得上。


















