更详细地解释 JOIN 与 LEFT JOIN 以及 WHERE 条件性能建议

问题描述 投票:0回答:2

这个候选答案中,断言在某些涉及某些

JOIN
子句的情况下
LEFT JOIN
WHERE
更好,因为它不会混淆查询规划器并且不是“毫无意义的”。断言/假设对任何人来说都应该是显而易见的。

请进一步解释或提供链接以供进一步阅读。

sql postgresql join left-join where-clause
2个回答
42
投票

实际上,

WHERE
条件和
JOIN
[INNER] JOIN
条件在 PostgreSQL 中是 100% 等效的。 (不过,使用显式
JOIN
条件使查询更易于阅读和维护是一个很好的做法)。

对于连接右侧表上的 LEFT JOIN

WHERE
条件的组合,
not
也是如此。
LEFT JOIN
的目的是保留连接左侧的所有行,无论右侧是否匹配。如果未找到匹配项,则该行将使用右侧列的空值进行扩展。 说明书:

LEFT OUTER JOIN

首先,执行内连接。然后,对于T1中不满足与T2中任何行的连接条件的每一行,连接行 在 T2 的列中添加空值。因此,连接表 T1 中的每一行始终至少有一行。

如果您随后应用一个

WHERE
条件,该条件要求右侧表的列上除空值之外的其他内容,则您将无效该效果并强制将
LEFT [OUTER] JOIN
转换为像普通
[INNER] JOIN
一样工作,只是(可能)由于查询计划更复杂,成本更高。

在具有许多连接表的查询中,Postgres(或任何 RDBMS)很难找到最佳(甚至是好的)查询计划。理论上连接表的可能序列数量会因子增长(!)。 Postgres 使用 “通用查询优化器” 来完成任务,并且有一些设置会影响它。

如上所述,使用误导性的

LEFT JOIN
来混淆查询,会使查询规划器的工作变得更加困难,会误导人类读者,并且通常会暗示查询逻辑中的错误。

由此产生的问题的相关解答:

等等


31
投票

考虑以下示例。我们有两个表,DEPARTMENTS 和 EMPLOYEES。

部分部门还没有员工。

此查询使用内部联接来查找员工 999 工作的部门(如果有),否则什么也不显示(甚至不显示员工或其姓名):

select a.department_id, a.department_desc, b.employee_id, b.employee_name
  from departments a
  join employees b
    on a.department_id = b.department_id
 where b.employee_id = '999'

下一个查询使用外连接(部门和员工之间的左连接)并查找员工 999 工作的部门。但是,如果员工不在任何部门工作,它也不会显示员工的 ID 或其姓名。这是因为 WHERE 子句中使用了外部连接表。如果没有匹配的部门,则将为空(不是 999,即使员工中存在 999)。

select a.department_id, a.department_desc, b.employee_id, b.employee_name
  from departments a
  left join employees b
    on a.department_id = b.department_id
 where b.employee_id = '999'

但是考虑这个查询:

select a.department_id, a.department_desc, b.employee_id, b.employee_name
  from departments a
  left join employees b
    on a.department_id = b.department_id
   and b.employee_id= '999'

现在标准位于 on 子句中。因此,即使该员工在任何部门工作,他仍然会被返回(他的 ID 和姓名)。部门列将为空,但我们得到结果(员工方面)。

您可能认为您永远不想在 WHERE 子句中使用外部连接表,但情况不一定如此。不过,由于上述原因,通常情况下是这样。

假设您希望所有部门都没有员工。然后您可以运行以下命令,它确实使用了外连接,并且外连接表在 where 子句中使用:

select a.department_id, a.department_desc, b.employee_id
  from departments a
  left join employees b
    on a.department_id = b.department_id
 where b.employee_id is null

^^ 显示没有员工的部门。

上述可能是您想要在 WHERE 子句而不是 ON 子句中使用外连接表的唯一合法原因(我认为这就是您的问题;内连接和外连接之间的区别是一个完全不同的主题) .

一个好的查看方法是:使用外连接来允许空值。那么为什么要使用外连接并规定字段不应为空且应等于“XYZ”?如果值必须是“XYZ”(非空),那么为什么要指示数据库允许返回空值呢?这就像说了一件事,然后又推翻它。

© www.soinside.com 2019 - 2024. All rights reserved.