查询优化器运算符选择 - 嵌套循环与散列匹配(或合并)

sta*_*ser 21 t-sql sql-server-2008 sql-execution-plan

我的一个存储过程执行时间过长.看一下查询执行计划,我能够找到操作耗时太长时间.它是一个嵌套的循环物理运算符,具有外部表(65991行)和内部表(19223行).在嵌套循环上,它显示估计行= ​​1,268,544,993(乘以65991乘19223),如下所示:

在此输入图像描述

我阅读了一些关于用于连接的物理运算符的文章,并且对于这种情况是否嵌套循环或散列匹配更好一点感到困惑.从我可以收集到的:

散列匹配 - 当没有有用的索引可用时,优化器使用散列匹配,一个表明显小于另一个表,表不在连接列上排序.散列匹配也可能表示可以使用更有效的连接方法(嵌套循环或合并连接).

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

谢谢

Eri*_*ikE 26

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

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

如果您已正确处理统计信息并且仍然存在问题,则可以强制它使用HASH连接,如下所示:

SELECT *
FROM
   TableA A -- The smaller table
   LEFT HASH JOIN TableB B -- the larger table
Run Code Online (Sandbox Code Playgroud)

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

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

  • 5-1 / 2年后,这也为我们解决了一个主要问题。谢谢!在我们的例子中,查询的“左侧”是递归CTE的结果。我们发现,QO将始终严重低估递归结果中的行数,因此,当我们编写子查询时,服务器选择了嵌套循环,并认为左侧只有3行。实际上,递归后,它超过了10,000行。这篇帖子促使我将一个位置重写为显式连接...,而75秒的查询变成了3秒的查询。:-) (2认同)

Gra*_*hey 10

我不建议通过强制提示朝一个方向或另一个方向"修复"计划.相反,您需要查看索引,统计信息和TSQL代码,以了解为什么有一个表盘从19000年加载了12亿行.