【问题标题】:Avoiding Nested Queries避免嵌套查询
【发布时间】:2011-02-16 06:04:02
【问题描述】:

避免嵌套查询有多重要。

我总是学会像躲避瘟疫一样避开它们。但它们对我来说是最自然的。当我设计一个查询时,我写的第一件事就是嵌套查询。然后我将其转换为连接,这有时需要很长时间才能正确。并且很少能带来很大的性能提升(有时确实如此)

他们真的那么糟糕吗?有没有办法在没有临时表和文件排序的情况下使用嵌套查询

【问题讨论】:

  • 我怀疑它在性能方面是否重要,至少在 MS SQL Server 中是这样。 MySQL 没那么聪明……

标签: sql mysql sql-server


【解决方案1】:

我不确定它在 MySQL 5.1 或 5.5 中的样子,但在 5.0.x 中,嵌套查询的性能通常很糟糕,因为 MySQL 对从主查询中获取的每一行执行子查询。 对于像 MsSQL 这样更成熟的数据库可能不是这种情况,它在内部可以将嵌套查询重写为连接,但我从未使用过 MsSQL,所以我不确定。

http://dev.mysql.com/doc/refman/5.0/en/rewriting-subqueries.html

同样,在某些情况下,不仅可以在没有子查询的情况下重写查询,而且使用其中一些技术比使用子查询更有效。 - 这是相当有趣的说法,考虑到到目前为止,所有子查询都会使数据库爬行。

Subqueries vs joins

【讨论】:

【解决方案2】:

这真的取决于,我曾经使用子查询改进了一些查询。

我知道的因素有:

  • 子查询是否使用外部查询中的字段进行比较(correlated 或不)
  • 如果外部查询和子查询之间的关系被索引覆盖
  • 如果连接上没有可用索引并且子查询不相关并返回一个小结果,则使用它可能会更快
  • 我也遇到过将使用 order by 的查询转换为不使用它的查询,而不是将其转换为简单的子查询和排序以提高 mysql 性能的情况

无论如何,测试不同的变体总是好的(请使用 SQL_NO_CACHE),将相关查询转换为连接是一个很好的做法。

我什至会说这是一种非常有用的做法。

如果相关查询是您首先想到的,您可能不是主要考虑集合操作,而是主要考虑过程操作,并且在处理关系数据库时,完全对数据模型和转换采取固定的观点。

编辑: 程序与关系
从集合操作与过程的角度思考可以归结为某些集合代数表达式中的等价性,例如联合上的选择等同于选择的联合。两者没有区别。
但是当你比较这两个过程时,例如将选择标准应用于联合的每个元素,然后应用选择,这两个过程是截然不同的,它们可能具有非常不同的属性(例如 CPU 的利用率,我/O,内存)。

关系数据库背后的理念是,您不尝试描述如何获得结果(过程),而只描述您想要的结果,并且数据库管理系统将决定满足您的请求的最佳路径(过程) .这就是为什么 SQL 被称为4th generation language (4GL)

帮助您做到这一点的技巧之一是提醒自己元组没有内在的顺序(集合元素是无序的)。 另一个是意识到关系代数非常全面,并且允许将请求(需求)直接转换为 SQL(如果您的模型的语义很好地代表了问题空间,或者换句话说,如果附加到您的表和关系的名称的含义是正确的) ,或者换句话说,如果您的数据库设计良好)。

因此,您不必考虑如何,只需考虑什么。

在您的情况下,这只是对相关查询的偏好,因此可能是我没有告诉您任何新内容,但您强调了这一点,因此发表了评论。

我认为,如果您完全熟悉将查询从一种形式转换为另一种形式的所有规则(rules,例如分配性),那么您不会更喜欢相关子查询(您会看到所有形式都是平等的)。

(注意:上面讨论了对数据库设计很重要的理论背景;实际上,上述概念有所不同——并非所有等效的查询重写都必须快速执行,聚集的主键确实使表在磁盘上具有继承顺序等。 . 但这些偏差只是偏差;并非所有等效查询都执行得这么快这一事实是实际 DBMS 的缺陷,而不是其背后的概念)

【讨论】:

  • 你有“从集合操作的角度思考”与“在程序操作的角度思考”的例子吗?
  • @Midhat:在答案中评论(编辑)。抱歉,如果不是您想要的,您是在寻找更实际的例子还是上面的解释?
【解决方案3】:

我个人更喜欢避免嵌套查询,直到它们是必要的,原因很简单,嵌套查询会降低代码的可读性,并使调试和协作更加痛苦。如果嵌套查询是微不足道的或者大型表的临时存储成为问题,我认为嵌套是可以接受的。但是我在嵌套查询中看到了太多次复杂的嵌套查询,这让调试很痛苦。

【讨论】:

    【解决方案4】:

    我尽量避免嵌套查询,因为它们的可读性较差。

    但我同意它们更容易编写。我的意思是,IMO 在编写代码时更容易概念化。但是,深度嵌套只会让阅读代码变得非常困难。让您添加一些注释来告诉读者子查询在做什么,这样他们就不需要阅读您的子查询,如果他们不需要。

    此外,一旦开始变得难以阅读,您可能需要考虑将子查询转换为公用表表达式。由于每个 CTE 都有特定的用途,因此转换很容易,也更易于阅读。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-27
      • 2020-05-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-09
      • 2016-11-19
      相关资源
      最近更新 更多