[英]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
会执行得更好。
EXISTS
和NOT EXISTS
都短路了——只要一条记录符合条件,它就会被包含或过滤掉,优化器就会转到下一条记录。
LEFT JOIN
将加入所有记录,无论它们是否匹配,然后过滤掉所有不匹配的记录。 如果您的表很大和/或您有多个JOIN
条件,这可能会非常耗费资源。
我通常会尽可能使用NOT EXISTS
和EXISTS
。 对于 SQL 服务器, IN
和NOT IN
在语义上是等效的,可能更容易编写。 这些是您可以在 SQL 服务器中找到的唯一可以保证短路的运算符。
我读过的关于 SQL 服务器的主题的最佳讨论在这里。
就个人而言,我认为这是一个很老的“它取决于”。 我见过每种方法都优于另一种的实例。
你最好的选择是测试两者,看看哪个表现更好。 如果在这种情况下表格总是很小并且性能并不那么重要,那么我只需 go 与您最清楚的那个(对于大多数人来说通常NOT EXISTS
存在)并继续前进。
这篇博客文章给出了各种方法的例子( NOT IN 、 OUTER APPLY 、 LEFT OUTER JOIN 、 EXCEPT和NOT 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.