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

Dwa*_*ell 12 sql postgresql join left-join where

这个候选答案中,断言它JOINLEFT JOIN在涉及某些WHERE子句的某些情况下更好,因为它不会混淆查询规划器并且不是"毫无意义".断言/假设是对任何人都应该是显而易见的.

请进一步解释或提供进一步阅读的链接.

Bri*_*lia 22

请考虑以下示例.我们有两个表,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'
Run Code Online (Sandbox Code Playgroud)

下一个查询使用外部联接(在部门和员工之间留下)并查找员工999为其工作的部门.但是,如果他们不在任何部门工作,也不会显示员工的身份证件或他或她的名字.这是因为在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'
Run Code Online (Sandbox Code Playgroud)

但请考虑以下查询:

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'
Run Code Online (Sandbox Code Playgroud)

现在标准在on子句中.因此,即使该员工在任何部门工作,他仍将被退回(他的身份证和姓名).部门列将为null,但我们得到一个结果(员工方).

您可能认为您永远不想在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
Run Code Online (Sandbox Code Playgroud)

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

以上可能是你想要在WHERE子句中使用外连接表而不是ON子句的唯一正当理由(我认为这是你的问题;内连接和外连接之间的区别是一个完全不同的主题).

一个好的方法是:你使用外连接来允许空值.那你为什么要使用外连接并说一个字段不应该为空并且应该等于'XYZ'?如果值必须是'XYZ'(非空),那么为什么要指示数据库允许空值返回?这就像说一件事,然后再覆盖它.

  • 这个答案中的第三个例子是错误的。在这种情况下将不会返回员工,该查询将返回 *所有部门* 和 *id 为 999* 的任何关联员工。如果 999 员工未与任何部门关联,则不会在结果中返回它们。 (3认同)

Erw*_*ter 20

实际上,WHERE条件和JOIN条件[INNER] JOIN在PostgreSQL中是100%等效的.(尽管使用显式JOIN条件使查询更易于阅读和维护,但这是一种很好的做法).

同样是没有一个真正LEFT JOIN具有组合WHERE上表条件的参与权.a的目的LEFT JOIN是保留连接左侧的所有行,而不管右侧是否匹配.如果未找到匹配项,则使用NULL右侧列的值扩展该行.手册:

LEFT OUTER JOIN

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

如果然后WHERE在右侧的表列上应用条件,则会使效果无效并强制转换LEFT JOIN为普通的工作JOIN,由于更复杂的查询计划而更加昂贵.

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

如上所述误导查询具有误导性LEFT JOIN,使得查询计划器的工作更加困难,对于人类读者来说是误导性的,并且通常暗示查询逻辑中的错误.

由此产生的问题的许多相关答案:

等等.

  • 如果它是或不是更昂贵,它会有什么不同.如果你要说表X上的值应该是某些东西(除了null)之外,为什么你会使用表X的外连接?如果有的话,不要仅仅因为它没有意义. (3认同)