inner join 通常比 left join 快,因其仅处理匹配行,支持剪枝、索引优化且无需生成 null;而 left join 需全量扫描左表并逐行查找右表匹配,空查和填充开销大,尤其右表无索引时更甚。

INNER JOIN 为什么通常比 LEFT JOIN 快
因为 INNER JOIN 只处理匹配行,数据库可以提前剪枝、利用索引快速定位交集,且无需为缺失匹配生成 NULL 占位;而 LEFT JOIN 必须扫描左表全量数据,并对每一行尝试在右表查找匹配——哪怕 90% 的左表记录在右表中根本不存在,这部分“空查”和 NULL 填充仍要执行。
- 右表无索引时,
LEFT JOIN的性能劣势会被放大:每条左表记录都可能触发一次全表扫描 -
INNER JOIN的结果集天然更小,后续排序、分组、网络传输开销都更低 - 某些查询优化器(如 PostgreSQL 14+、MySQL 8.0)会对
INNER JOIN启用哈希连接或物化中间结果,但对LEFT JOIN往往保留嵌套循环以保证语义正确性
LEFT JOIN 不一定慢,但容易被写成“伪 INNER JOIN”
最常见陷阱是:在 LEFT JOIN 后加了 WHERE 条件过滤右表字段,比如 WHERE orders.amount > 100。这会让原本应保留的无订单用户(orders.amount IS NULL)被直接过滤掉,最终效果等价于 INNER JOIN,却承担了 LEFT JOIN 的全部执行开销。
- 正确写法:把右表过滤条件移到
ON子句里,例如LEFT JOIN orders ON users.id = orders.user_id AND orders.amount > 100 -
ON是连接时生效的逻辑,WHERE是连接后生效的过滤——这个区别决定你是否真的需要左表全量 - 执行计划里若看到
Filter: orders.amount > 100出现在JOIN节点之后,基本就是踩坑了
什么时候该坚持用 LEFT JOIN,哪怕它慢一点
当业务逻辑明确要求“展示主表全部数据”,比如报表中列出所有销售员及其成交额(含 0 单员)、后台导出全部用户及其最近登录时间(含从未登录者),这时性能让位于语义正确性。强行改用 INNER JOIN 会漏数据,再快也没用。
- 先确认需求:是不是真要“左表一行都不能少”?如果只是“大部分有匹配”,那可能是设计问题,不是 SQL 问题
- 可考虑预聚合:比如先把
orders按user_id分组统计,再LEFT JOIN聚合结果,比直接连明细表快得多 - 大表
LEFT JOIN小表一般可控;小表LEFT JOIN超大事实表(如日志表),务必加索引或分区裁剪
看执行计划比猜“哪个 JOIN 更快”有用得多
不同数据库、不同数据分布下,INNER JOIN 和 LEFT JOIN 的实际耗时可能反转。比如右表极小且内存可容纳,LEFT JOIN 的哈希构建反而比 INNER JOIN 的多次索引探查更快。
- 用
EXPLAIN ANALYZE(PostgreSQL)、EXPLAIN FORMAT=JSON(MySQL)或 SSMS 的执行计划图形界面,盯住 Rows Removed by Filter、Actual Total Time、Loop Count 这几项 - 特别注意 Nested Loop 是否出现 “never executed” 或 “actual rows = 0”,这说明优化器已跳过无效分支
- 别只看 “Join Type” 字样,重点看驱动表是谁、连接算法选了 Hash/Sort Merge/Nested Loop、有没有回表
ON 和 WHERE 的边界划清楚,比纠结用哪个 JOIN 更重要。










