【问题标题】:Why does a SQL join choose a sub-optimal query plan?为什么 SQL 连接会选择次优查询计划?
【发布时间】:2009-12-05 15:15:30
【问题描述】:

好的,我意识到这是一个非常模糊的问题,但请耐心等待。

我在很多场合都遇到过这个问题,有不同的和不相关的查询。下面的查询需要很长时间才能执行:

SELECT <Fields>
FROM <Multiple Tables Joined>
    LEFT JOIN (SELECT <Fields> FROM <Multiple Tables Joined> ) ON <Condition>

但是,只需添加连接提示,它就可以在几秒钟内执行查询:

SELECT <Fields>
FROM <Multiple Tables Joined>
    LEFT HASH JOIN (SELECT <Fields> FROM <Multiple Tables Joined> ) ON <Condition>

奇怪的是,提示中指定的 JOIN 类型并不能真正提高性能。似乎是因为提示导致优化器孤立地执行子查询然后加入。如果我为子查询创建一个表值函数(不​​是内联函数),我会看到相同的性能改进。例如

SELECT <Fields>
FROM <Multiple Tables Joined>
    LEFT JOIN dbo.MySubQueryFunction() ON <Condition>

有人知道为什么优化器在这种情况下如此愚蠢吗?

【问题讨论】:

  • 您使用的是什么版本的 SQL Server?
  • 我在 2005 年和 2008 年都遇到过这个问题

标签: sql sql-server


【解决方案1】:

如果这些表中的任何一个是表变量,则优化器会使用错误的 0 行估计值,并且通常选择嵌套循环作为连接技术。

这样做是因为缺少有关表的统计信息。

【讨论】:

  • 我没有使用表变量,但子查询中经常有视图。不过,你的推理对我来说确实有意义。
  • 当我删除连接提示时,查询计划发生了很大变化,并且确实引入了嵌套循环。我找不到它对行的错误估计的地方,但我不能再花时间寻找了。
【解决方案2】:

优化器是一种算法。它既不笨也不聪明,它按照编程的方式工作。

Hash join 意味着在较小的行源上构建哈希表,这就是为什么必须先执行内部查询。

在第一种情况下,优化器可能选择了nested loop。它将连接条件推送到内部查询中,并在每次迭代时使用附加谓词执行内部查询。它可能找不到适合该谓词的索引,并且每次迭代都会发生full table scan

除非您发布确切的查询以及表中有多少行,否则很难说为什么会发生这种情况。

使用表函数,不可能将连接条件推送到内部查询中,这就是它只执行一次的原因。

【讨论】:

  • 我同意这似乎正在发生。我只是不知道为什么优化器选择做一个嵌套循环。
  • 很难说,我们需要看到准确的查询以及表中有多少行。
  • 我已经尝试减少查询,但在重现问题的同时我能得到的最小查询是 43 行。我不想在没有数据库的情况下尝试分析它的痛苦。
【解决方案3】:

深入了解 SQL Server 2005:T-SQL 查询回答了这些问题以及许多其他问题。我见过的 T-SQL 数据检索和动词处理的最佳外观之一。 (不,我不是这本书的作者,我也不隶属于这本书的任何一位或多位作者,或者微软或微软出版社。这简直是一部令人难以置信的作品,我过去曾转向过各种 DBA几年同意。)

【讨论】:

  • 我知道 Itzik - 他可能是这个星球上最聪明的 SQL 人之一。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-14
  • 1970-01-01
  • 2016-03-05
  • 2019-10-20
  • 1970-01-01
  • 2013-12-24
  • 1970-01-01
相关资源
最近更新 更多