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

yws3nbqq  于 5个月前  发布在  PostgreSQL
关注(0)|答案(2)|浏览(107)

this candidate answer中,AssertJOIN在某些情况下比LEFT JOIN好,因为它不会混淆查询规划器,也不是“无意义的”。Assert/假设是任何人都应该显而易见。
请进一步解释或提供进一步阅读的链接。

oipij1gg

oipij1gg1#

实际上,[INNER] JOINWHERE条件和JOIN条件在PostgreSQL中是100%等效的。(不过,使用显式的JOIN条件使查询更容易阅读和维护是一个好的做法)。
对于LEFT JOINWHERE条件组合在连接右侧的表上,情况也是如此。LEFT JOIN的目的是保留连接左侧的所有行,而不管右侧是否匹配。如果没有找到匹配,则将右侧的列扩展为空值。手册:
LEFT OUTER JOIN
首先,执行内部联接。然后,对于T1中与T2中的任何行都不满足联接条件的每一行,在T2的列中添加一个具有空值的联接行。因此,联接表中的T1中的每一行始终至少有一行。
如果您随后应用一个WHERE条件,该条件要求在右侧表的列上使用除空值以外的其他值,则会使效果无效,并强制将LEFT [OUTER] JOIN转换为普通的[INNER] JOIN,只是(可能)由于更复杂的查询计划而更昂贵。
在一个有许多连接表的查询中,Postgres(或任何RDBMS)很难找到最好的(甚至是一个好的)查询计划。理论上可能连接表的序列的数量 factorially(!)。Postgres使用“Generic Query Optimizer”来完成任务,并且有一些设置来影响它。
使用误导性的LEFT JOIN混淆查询,使查询规划器的工作更加困难,对人类读者来说是误导性的,通常暗示查询逻辑中的错误。
由此产生的问题的相关解答:

  • 为什么在WHERE中null等于integer?
  • 使用LEFT JOIN的查询不返回计数为0的行
  • 使用外部连接并限制每个父记录的子记录的SQL查询
  • 左外联接的作用类似于内联接
  • 选择其他表中不存在的行

0tdrvxhp

0tdrvxhp2#

考虑下面的例子,我们有两个表,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和姓名)。部门列将为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


显示没有员工的部门。
以上可能是您希望在WHERE子句中使用外部连接表而不是ON子句的唯一合理原因(我认为这就是您的问题所在;内部和外部连接之间的区别是一个完全不同的主题)。
一个很好的方法是这样的:你使用外部连接来允许空值。为什么你要使用外部连接并说一个字段不应该是空值,应该等于'XYZ'?如果一个值必须是'XYZ'(不是空值),那么为什么要指示数据库允许空值返回?这就像说了一件事,然后覆盖它。

相关问题