繁体   English   中英

SQL 左外连接与不存在的性能

[英]SQL performance on LEFT OUTER JOIN vs NOT EXISTS

如果我想在表 A 中但不在表 B 中找到一组条目,我可以使用 LEFT OUTER JOIN 或 NOT EXISTS。 我听说 SQL 服务器面向 ANSI,在某些情况下,左外连接比不存在更有效。 在这种情况下,ANSI JOIN 会表现更好吗? 在 SQL 服务器上,连接运算符是否比 NOT EXISTS 更有效?

Joe 的链接是一个很好的起点。 Quassnoi 也涵盖了这一点。

通常,如果您的字段被正确索引,或者如果您希望过滤掉更多记录(即子查询中有很多行EXIST ), NOT EXISTS会执行得更好。

EXISTSNOT EXISTS都短路了——只要一条记录符合条件,它就会被包含或过滤掉,优化器就会转到下一条记录。

LEFT JOIN将加入所有记录,无论它们是否匹配,然后过滤掉所有不匹配的记录。 如果您的表很大和/或您有多个JOIN条件,这可能会非常耗费资源。

我通常会尽可能使用NOT EXISTSEXISTS 对于 SQL 服务器, INNOT IN在语义上是等效的,可能更容易编写。 这些是您可以在 SQL 服务器中找到的唯一可以保证短路的运算符。

我读过的关于 SQL 服务器的主题的最佳讨论在这里

就个人而言,我认为这是一个很老的“它取决于”。 我见过每种方法都优于另一种的实例。

你最好的选择是测试两者,看看哪个表现更好。 如果在这种情况下表格总是很小并且性能并不那么重要,那么我只需 go 与您最清楚的那个(对于大多数人来说通常NOT EXISTS存在)并继续前进。

这篇博客文章给出了各种方法的例子( NOT INOUTER APPLYLEFT OUTER JOINEXCEPTNOT EXISTS )来实现相同的结果,并证明不存在(左反半连接)是冷缓存和热缓存中的最佳选择情景。

我一直想知道在 OP 描述的这些情况下,我们如何使用要删除的表上的索引。

假设我们有:

 table EMPLOYEE (emp_id int, name varchar) 
and
 table EMPLOYEE_LOCATION (emp_id int, loc_id int)

在我的真实示例中,我的表要宽得多,包含超过 100 万行,出于示例目的,我已经简化了模式。

如果我想从 EMPLOYEE_LOCATION 中删除在 EMPLOYEE 中没有相应 emp_id 的行,我显然可以使用左外部技术或 NOT IN 但我想知道......

如果两个表都具有 emp_id 前导列的索引,那么是否值得尝试使用它们?

也许我可以从 EMPLOYEE 中提取 emp_id,从 EMPLOYEE_LOCATION 中提取 emp_id 到一个临时表中,然后从我要删除的临时表中获取 emp_id。

然后我可以循环这些 emp_id 并实际使用索引,如下所示:

loop for each emp_id X to delete -- (this would be a cursor)
 DELETE EMPLOYEE_LOCATION WHERE emp_id = X

我知道 cursor 存在开销,但在我的真实示例中,我正在处理巨大的表,所以我认为明确使用索引是可取的。

在 dba.stackexchange 上回答

我注意到一个例外,即NOT EXISTS优于LEFT JOIN... WHERE IS NULL是在使用Linked Servers时。

通过检查执行计划,似乎NOT EXISTS运算符以嵌套循环方式执行。 因此它是按行执行的(我认为这是有道理的)。

演示此行为的示例执行计划: 在此处输入图像描述

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM