ON决定连接条件,WHERE在连接后过滤;外连接中错将条件放WHERE会使LEFT JOIN退化为INNER JOIN;多表JOIN时ON只能引用相邻两表字段;NULL判断须用IS NOT NULL。

JOIN 用 ON 还是 WHERE?先看执行逻辑
ON 是 JOIN 的一部分,决定“哪些行能被连进来”;WHERE 是 JOIN 完成后才过滤的。如果把本该写在 ON 里的条件错放 WHERE,外连接(LEFT JOIN)会退化成内连接——这是最常踩的坑。
-
LEFT JOIN ... ON a.id = b.a_id AND b.status = 'active':保留所有 a 表记录,b 表只匹配 status 为 active 的行(没匹配上的 b 字段为 NULL) -
LEFT JOIN ... ON a.id = b.a_id WHERE b.status = 'active':先全量 LEFT JOIN,再筛出 b.status 不为 NULL 的行,结果等价于INNER JOIN - 多表 JOIN 时,每个
ON只管它左边的表和右边那个表,不能跨表引用(比如三表 JOIN 中,第二个ON不能直接引用第一张表的字段,除非用子查询或 CTE)
INNER JOIN 和 LEFT JOIN 在 NULL 处理上怎么选
想查“有订单的用户”,用 INNER JOIN;想查“所有用户,不管有没有订单”,必须用 LEFT JOIN,但得注意后续字段是否允许 NULL。
-
LEFT JOIN orders o ON u.id = o.user_id后,o.amount可能为 NULL,直接SUM(o.amount)会忽略 NULL 行,但COUNT(o.id)和COUNT(*)结果不同(前者不计 NULL,后者计所有行) - 判断关联是否存在,别写
o.id != NULL,要写o.id IS NOT NULL—— NULL 不能用!=或=比较 - MySQL 8.0+ 和 PostgreSQL 支持
LEFT JOIN ... USING (col),比ON简洁,但要求列名、类型、含义完全一致,别为了省字符硬套
ON 条件里能用函数或表达式吗?性能怎么看
能用,但多数情况下会拖慢速度,尤其当函数作用于被 JOIN 的字段时(比如 ON UPPER(a.name) = UPPER(b.name)),数据库很难走索引。
- 优先让 JOIN 字段保持“裸值”:建索引前统一大小写、去空格,而不是每次 JOIN 都调用
TRIM(UPPER()) - PostgreSQL 支持函数索引(
CREATE INDEX ON t (UPPER(name))),MySQL 8.0+ 也支持,但需显式创建,不会自动生效 - 避免在
ON里写子查询(如ON a.id = (SELECT id FROM x WHERE ...)),某些引擎会转成循环嵌套,数据量大时直接卡死
JOIN 太多查不动?先看执行计划再动手
5 张表 JOIN 不一定慢,5 张表没索引 + 错误 ON 条件 + 返回大量字段,才真慢。别一上来就拆 SQL,先看 EXPLAIN 输出。
- MySQL 用
EXPLAIN FORMAT=TREE看实际连接顺序;PostgreSQL 用EXPLAIN (ANALYZE, BUFFERS)看真实 IO 和行数 - 关注
type(MySQL)或Node Type(PG)字段:出现ALL或Seq Scan且 rows 很大,说明缺索引或条件没打到索引上 - 临时表(
Using temporary)、文件排序(Using filesort)出现在 JOIN 后,大概率是 SELECT 列太多或 GROUP BY / ORDER BY 没走索引
关联字段类型不一致(比如一边是 VARCHAR(50),一边是 CHAR(50) 或 TEXT)会导致隐式转换,索引失效——这个点容易被忽略,查半天执行计划都对,就是跑得慢。

















