【问题标题】:query optimizer operator choice - nested loops vs hash match (or merge)查询优化器运算符选择 - 嵌套循环与哈希匹配(或合并)
【发布时间】:2012-01-17 15:02:09
【问题描述】:

我的一个存储过程执行时间过长。查看查询执行计划,我发现该操作花费的时间太长。它是一个嵌套循环物理运算符,具有外部表(65991 行)和内部表(19223 行)。在嵌套循环中,它显示估计行数 = 1,268,544,993(将 65991 乘以 19223),如下所示:

我阅读了几篇关于用于连接的物理运算符的文章,有点困惑嵌套循环或哈希匹配是否更适合这种情况。从我能收集到的:

哈希匹配 - 当没有有用的索引可用时由优化器使用,一个表比另一个小得多,表未按连接列排序。哈希匹配也可能表明可以使用更有效的连接方法(嵌套循环或合并连接)。

问题:在这种情况下,哈希匹配会比嵌套循环更好吗?

谢谢

【问题讨论】:

  • 请发布查询。您始终可以使用查询提示来强制使用特定的连接类型和连接顺序,并比较两者的SET STATISTICS IO ON;SET STATISTICS TIME ON; 的输出(假设连接实际上是一个等连接,因此哈希连接甚至更合适?)
  • 您应该替换“Clustered Index Scan”来查找和显示您的脚本。
  • 如果你有一天回到stackoverflow,如果你选择一个答案会很好。 :)

标签: sql-server-2008 tsql sql-execution-plan


【解决方案1】:

绝对。哈希匹配将是一个巨大的改进。在较小的 19,223 行表上创建散列,然后使用较大的 65,991 行表对其进行探测,这比需要 1,268,544,993 行比较的嵌套循环小得多。

服务器选择嵌套循环的唯一原因是它严重低估了所涉及的行数。您的表格是否有关于它们的统计信息,如果有,它们是否会定期更新?统计数据使服务器能够选择好的执行计划。

如果您已正确处理统计信息但仍有问题,您可以强制它使用 HASH 连接,如下所示:

SELECT *
FROM
   TableA A -- The smaller table
   LEFT HASH JOIN TableB B -- the larger table

请注意,当您执行此操作时,它也会强制加入顺序。这意味着您必须正确排列所有表,以便它们的连接顺序有意义。通常,您会检查服务器已有的执行计划并更改查询中表的顺序以匹配。如果您不熟悉如何执行此操作,则基本是每个“左”输入都排在第一位,而在图形执行计划中,左输入是 lower 的。涉及许多表的复杂连接可能必须在括号内将连接组合在一起,或使用RIGHT JOIN 以获得最佳执行计划(交换左右输入,但在连接顺序中的正确位置引入表) .

通常最好避免使用连接提示和强制连接顺序,所以先做任何你能做的事情!您可以查看表上的索引、碎片、减小列大小(例如在不需要 Unicode 的情况下使用 varchar 而不是 nvarchar),或将查询拆分为多个部分(先插入临时表,然后加入到那个)。

【讨论】:

  • 3 年后,你只是帮我解决了一个问题。谢谢!
  • 很高兴听到这个消息。是问题统计信息,还是您只需要推出连接提示和强制连接顺序?
  • 5-1/2 年后,这也为我们解决了一个主要问题。谢谢!在我们的例子中,查询的“左侧”是递归 CTE 的结果。我们发现 QO 总是会严重低估递归结果中的行数,所以当我们编写子查询时,服务器会选择嵌套循环,认为左边只有 3 行。实际上,在递归之后,它有超过 10,000 行。这篇文章促使我将那个位置重写为显式连接......并且一个 75 秒的查询变成了一个 3 秒的查询。 :-)
  • @JohnM.Black 请记住加入提示强制加入顺序。您最好包含一条注释,说明向查询中添加更多表可能是有害的。考虑改为插入临时表。很高兴我能帮上忙。
【解决方案2】:

我不建议尝试通过向一个方向或另一个方向强制提示来“修复”计划。相反,您需要查看您的索引、统计信息和 TSQL 代码,以了解为什么您的 Table spool 加载了 19000 年以来的 12 亿行。

【讨论】:

    猜你喜欢
    • 2021-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-07
    • 1970-01-01
    • 2011-03-04
    相关资源
    最近更新 更多