MySQL 的 `EXPLAIN` 输出中,`filtered` 属性使用

通过以下两个 SQL 执行计划,没有太大差异,唯有 filtered 属性数值不一样

sql 复制代码
    
    select
    count(1)
    from payment_log c
    INNER JOIN  user_relation r ON r.user_id = c.uid
    left join user u on c.uid = u.id
    where
        ( c.start_time <=  '2025-12-31' AND c.start_time >=  '2024-01-01'
      or c.end_time <=  '2025-12-31' AND c.end_time >=  '2024-01-01')
sql 复制代码
   select
    count(1)
    from payment_log c
    INNER JOIN  user_relation r ON r.user_id = c.uid
    left join user u on c.uid = u.id
    where NOT (c.end_time < '2024-01-01' OR c.start_time > '2025-12-31');

在 MySQL 的 EXPLAIN 输出中,filtered 属性表示经过 WHERE 条件过滤后,预计保留的行百分比。它是一个估算值,用于帮助优化器评估查询效率。


🔍 filtered 值的意义

  • 值越小越好 ✅

    • 表示经过 WHERE 条件过滤后,只有较少比例的数据被保留,说明条件更"精确",能有效减少需要处理的数据量。
    • 例如:filtered=10.00 表示该表中大约有 10% 的数据满足当前查询条件。
  • 值较大(接近 100)⚠️

    • 表示 WHERE 条件不够精准,几乎整张表的数据都需要处理,可能导致性能问题,尤其是大表。
    • 这时应考虑:
      • 是否缺少合适的索引
      • SQL 条件是否可以进一步优化
      • 是否使用了不支持索引的操作(如函数、通配符开头的 LIKE)

📌 示例解释

假设你看到如下 EXPLAIN 输出:

复制代码
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra          |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+----------------+
|  1 | SIMPLE      | c     | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 583189 |    11.11 | Using where    |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+----------------+
  • rows=583189:表示 MySQL 预计要扫描约 58 万行数据。
  • filtered=11.11:表示最终只保留约 11% 的数据(即约 6.4 万行),虽然这个值不算高,但因为扫描基数太大,整体性能仍然可能较差。

✅ 如何提升 filtered 的效率?

1. 添加合适索引

确保查询字段上有合适的索引,特别是 WHEREJOINORDER BY 中使用的字段。

2. 优化 SQL 写法

避免全表扫描,改写复杂的 OR 条件为等效但更易优化的形式(如 NOT (end_time < x OR start_time > y))。

3. 使用覆盖索引(Covering Index)

创建包含查询所需所有字段的索引,避免回表查询。

4. 减少不必要的 JOIN 或子查询

有时可以通过提前过滤或重写查询逻辑来减少数据处理量。


🧪 实际建议

根据你之前的 SQL 查询和执行计划:

sql 复制代码
AND NOT (c.end_time < #{interviewDate1} OR c.start_time > #{interviewDate2})

start_timeend_time 上没有索引,即使 filtered 较小,也会因为扫描大量数据而影响性能。

✅ 推荐操作:

  1. 创建组合索引 (start_time, end_time)
  2. 使用 EXPLAIN 检查优化后的执行计划是否命中索引并显著降低 rows 和提高过滤效率

📌 总结

指标 理想状态 原因
filtered 越小越好 表示 WHERE 条件更精确,减少无效数据处理
rows 越小越好 扫描行数越少,性能越高
Extra 不出现 Using filesort / Using temporary 表示排序或分组未使用索引
相关推荐
float_六七5 分钟前
SQL预编译:安全高效数据库操作的关键
数据库·sql·安全
写代码也要符合基本法1 小时前
Oracle SQL - 使用行转列PIVOT减少表重复扫描(实例)
数据库·sql·oracle
刺客xs1 小时前
MYSQL数据库----DCL语句
android·数据库·mysql
胖墩的IT1 小时前
在高并发场景下,仅依赖数据库机制(如行锁、版本控制)无法完全避免数据异常的问题
数据库·mysql
iReaShare1 小时前
如何将数据从一部手机传输到另一部手机?
android
慢行的骑兵2 小时前
Android音视频探索之旅 | C++层使用OpenGL ES实现视频渲染
android·音视频·ndk
天天爱吃肉82182 小时前
汽车嵌入式开发:如何构建「不可替代」的核心竞争力?
数据库·汽车
iReaShare2 小时前
将CSV联系人导入安卓手机的3种简单方法
android
彬彬醤2 小时前
ChatGPT无法登陆?分步排查指南与解决方案
服务器·网络·数据库·网络协议·chatgpt