何时使用SQL子查询而不是标准连接?

44

我正在重写一些编写不良的SQL查询语句,它们过度使用子查询。我正在寻找有关使用子查询的最佳实践。

非常感谢您的帮助。


2
并不是说没有万能解决方案——问题在于这个问题太过宽泛,无法得到合理的答案。不能保证在一个数据库(MySQL)上有效的方法也一定适用于另一个数据库。最简单的规则是,如果子查询中的列出现在最终结果集中,请使用JOIN——这是从两个表中获取数据的最优方式。否则,子查询也可以,但相关子查询可能会导致问题(尽管EXISTS不会)。 - OMG Ponies
1
你根据什么来说子查询被过度使用了?似乎很奇怪先下定论,然后再询问如何最佳实践使用子查询的信息。 - Larry Lustig
2
可能是Join vs. sub-query的重复问题。 - Ciro Santilli OurBigBook.com
1
@OMGPonies,你最简单的规则和AskTom一样,“连接/子查询在语义上是不同的。 *当您不需要从引用子查询中的表获取列时,请使用子查询。 当您确实需要某些列时,请使用连接。 select * from emp where deptno in ( select deptno from dept ); 比 select emp. from emp, dept where emp.deptno = dept.deptno; “更好”。 而且请记住,不能简单地用连接替换子查询(反之亦然),因为它们经常会得到不同的答案。 - ExcessOperatorHeadspace
3个回答

59

子查询通常没问题,除非它们是相关子查询(也称为关联子查询)。如果您只使用独立子查询,并且它们使用适当的索引,则应该可以快速运行。如果你有一个依赖子查询,你可能会遇到性能问题,因为一个依赖子查询通常需要针对外部查询中的每一行运行一次。所以,如果您的外部查询有1000行,那么子查询将运行1000次。另一方面,独立子查询通常只需要评估一次。

如果您不确定什么是依赖或独立子查询,这里有一个经验法则 - 如果您可以从上下文中移除子查询,运行它并获得结果集,则它是一个独立子查询

如果出现语法错误,因为它引用了子查询之外的某些表,则它是一个依赖子查询

当然,一般规则有一些例外。例如:

  • 许多优化器可以接受依赖子查询并找到以JOIN方式有效运行它的方法。例如,NOT EXISTS查询可能会导致反连接查询计划,因此它不一定比使用JOIN编写的查询更慢。
  • MySQL有一个错误,其中IN表达式中的独立子查询被错误地识别为依赖子查询,因此将使用次优的查询计划。这在最新版本的MySQL中已经修复了。

如果性能是一个问题,那么测量您特定的查询并查看哪种方法最好。


你的意思是指包含了外部查询中某个列的引用吗? - El Ronnoco
3
许多优化器可以接受一个依赖子查询并找到一种有效运行它的方法。我同意这个说法,它否定了你的整个论点,即“相关子查询是不好的,除非它们不是不好的”。 - onedaywhen

7

这里没有银弹。每种用法都必须独立评估。有些情况下,相关子查询明显效率低下,下面的例子最好改为使用JOIN。

select nickname, (select top 1 votedate from votes where user_id=u.id order by 1 desc)
from users u

另一方面,EXISTS和NOT EXISTS查询将优于JOIN。

select ...
where NOT EXISTS (.....)

通常比其他方式更快。
select ...
FROM A LEFT JOIN B
where B.ID is null

然而,即使是这些概括也可能对于任何特定的模式和数据分布都不正确。


4

不幸的是,答案很大程度上取决于您使用的SQL服务器。从纯关系理论的角度来看,连接更好。它们让服务器在幕后做正确的事情,并给予它们更多的控制权,因此最终可能会更快。 如果 服务器实现得好的话。实际上,一些SQL服务器通过子查询等技巧来优化查询时表现更好。


一些子查询也可以转换为连接(当然,这取决于服务器)。对于大多数情况,我发现连接更符合我的思维方式。 - user166390
不,如果服务器实现得好,它将识别执行JOIN或子查询的最快方式,并生成最优执行计划。如果JOIN和子查询在代数上是相同的,则良好实现的服务器将生成相同的执行计划。 - Larry Lustig
是的...都是真的。如果服务器被完美实现,它会始终优化您的错误查询;-) 但是...这也是我观点的大部分内容:如果按照其行为构建查询,几乎所有的SQL服务器都会表现更好。这是一个不幸的事实。一般来说,产品存在的时间越长,无论如何构造查询,使用它都可能会做得更好。但即使如此,也并非总是如此。 - Wes Hardaker
1
“根据纯关系理论的观点,连接更好”的说法是荒谬的。需要考虑到,在支持子查询之前,SQL在Codd的代数方面不是关系完备的。” - onedaywhen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接