最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
为何在SQL中先Filter后Join比先Join后Filter更高效?
时间:2026-07-03 10:55:46 编辑:袖梨 来源:一聚教程网
先Filter再Join更快,因中间结果集缩小使JOIN计算量断崖下降;WHERE若不可下推(如含OR、LIKE、函数)则失效,需用子查询或CTE显式控制过滤时机。
因为中间结果集大小直接决定JOIN的计算量,先Filter能把百万行压到几百行,JOIN开销自然断崖式下降。
WHERE条件写在JOIN后 vs 子查询里,执行计划差异巨大
数据库执行顺序是 FROM → ON → JOIN → WHERE,但优化器是否能把WHERE下推,取决于表达式是否可下推。遇到OR、LIKE '%abc'、DATE(created_at)这类,MySQL 8.0+和PostgreSQL大概率放弃下推,导致先全表JOIN再过滤。
- 查执行计划时重点看
rows字段:如果orders表显示扫描200万行,但实际满足status = 'PAID'的只有8000行,说明过滤没提前 - 用子查询显式控制:例如
(SELECT * FROM orders WHERE status = 'PAID')作为右表,让驱动行数从10万降到8000 - CTE在PostgreSQL中更易读,但MySQL 8.0+也支持,语义等价,都比裸
WHERE可靠
LEFT JOIN里把右表条件放WHERE里,等于悄悄转成INNER JOIN
ON决定“怎么连”,WHERE决定“连完留哪些”。对LEFT JOIN,把右表字段条件写在WHERE里,会把左表没匹配的行全踢掉——语义已变,性能也崩。
- 错误写法:
LEFT JOIN orders o ON u.id = o.user_id WHERE o.created_at > '2025-01-01'→ 没订单的用户消失 - 正确写法:
LEFT JOIN (SELECT * FROM orders WHERE created_at > '2025-01-01') o ON u.id = o.user_id→ 用户全量保留,orders只扫1/10行 - 如果必须用
WHERE,得改成WHERE o.created_at > '2025-01-01' OR o.created_at IS NULL,但逻辑复杂且难走索引
聚合查询不先GROUP BY再JOIN,就是在喂数据库吃内存
订单+用户+商品三表JOIN后再COUNT(),中间结果可能是千万级;而先按user_id聚合订单,再JOIN用户信息,JOIN对象只是几百行的汇总表。
- 慢写法:
SELECT u.name, COUNT(o.id) FROM users u LEFT JOIN orders o ON u.id = o.user_id GROUP BY u.id→orders全量参与JOIN - 快写法:
SELECT u.name, t.cnt FROM users u LEFT JOIN (SELECT user_id, COUNT(*) cnt FROM orders GROUP BY user_id) t ON u.id = t.user_id - 注意:子查询里的
GROUP BY必须包含JOIN键(如user_id),否则关联失效
真正容易被忽略的是:即使用了子查询,如果orders表上没有status或created_at的索引,子查询本身仍是全表扫描——Filter再早,没索引也白搭。
相关文章
- 刀剑缭乱2026公测兑换码大全一览 07-05
- 崩坏星穹铁道4.0卡池7个新角色一览 07-05
- 明日方舟终末地开服工业蓝图一览 工业蓝图作用与使用思路解析 07-05
- 原神梦之树怎么开启 梦之树开启条件 07-05
- 帕瓦勇者传说持续伤害阵容搭配推荐 07-05
- 明日方舟:终末地全新玩法 蚀像寻遗怎么玩介绍 07-05