仅仅通过JOIN指定HASH JOIN的优势?

时间:2009-04-28 22:37:58

标签: sql-server tsql join sql-server-2005 join-hints

在常规JOIN上显式执行HASH JOIN有哪些优势(如果有的话)(其中SQL Server将决定最佳的JOIN策略)?例如:

select pd.*
from profiledata pd
inner hash join profiledatavalue val on val.profiledataid=pd.id

在上面的简单示例代码中,我指定了JOIN策略,而如果我省略“hash”关键字,SQL Server将在幕后执行MERGE JOIN(根据“实际执行计划”)。 / p>

5 个答案:

答案 0 :(得分:13)

optmiser在日常使用中做得非常好。然而,从理论上讲,可能需要3周时间才能找到完美的计划,因此生成的计划有可能不理想。

除非你有一个非常复杂的查询或大量的数据,否则我就不管它是什么,它根本无法产生一个好的计划。然后我会考虑它。

但随着时间的推移,随着数据的变化/增长或索引的变化等,您的JOIN提示将变得过时并阻止最佳计划。 JOIN提示只能在开发时使用您拥有的那组数据优化该单个查询。

就个人而言,我从未在任何生产代码中指定JOIN提示。

我通常通过更改查询,添加/更改索引或将其分解来解决错误的联接(例如,首先加载临时表)。或者我的查询错误,或者我进行了隐式数据类型转换,或者突出显示了我的架构中的缺陷等。

我见过其他开发人员使用它们,但只有在复杂视图嵌套的情况下才会使用它们,并且在重构时会导致后来的问题。

编辑:

我今天进行了转换,其中一些同事将使用它们来强制执行错误的查询计划(使用NOLOCK和MAXDOP 1)来“鼓励”迁移远离其下游系统之一直接调用的传统复杂嵌套视图。

答案 1 :(得分:3)

何时尝试哈希提示,如何:

  • 检查至少一个上有足够的索引 表。
  • 尝试重新排列查询后。转换等事情 加入" in"或者"存在",改变连接顺序(实际上只是一个 无论如何提示),将逻辑从where子句移动到连接条件等。

关于何时散列连接有效的一些基本规则是当连接条件不作为表索引存在以及表大小不同时。如果您正在寻找技术描述,那么有关于散列连接如何工作的一些很好的描述。

为什么要使用任何连接提示(带有强制命令副作用的哈希/合并/循环)?

  • 避免极端缓慢执行(.5 - > 10.0s)角落案件。
  • 当优化程序一直选择平庸的计划时。

在某些情况下,提供的提示可能不是理想的,但可以提供更一致的可预测运行时。在使用提示时,应预先测试预期的最坏情况和最佳情况。可预测的运行时间对于Web服务至关重要,其中优先考虑的标称[.3s,.6s]严格优于[.25,10.1s]范围内的查询。随着新近更新的统计数据和遵循的最佳实践,可能会发生大的运行时差异。

在开发环境中进行测试时,应该关闭"作弊"以及避免热/冷运行时间差异。来自另一个post ...

CHECKPOINT -- flushes dirty pages to disk
DBCC DROPCLEANBUFFERS -- clears data cache
DBCC FREEPROCCACHE -- clears execution plan cache

最后一个选项可能与选项(重新编译)提示相同。

MAXDOP和机器的加载也可以在运行时产生巨大的差异。将CTE物化为临时表也是一种很好的锁定机制,需要考虑。

答案 2 :(得分:2)

Hash加入并行化和扩展比任何其他连接更好,并且非常适合最大化数据仓库中的吞吐量。

答案 3 :(得分:1)

我在运输代码中看到的唯一提示是OPTION(FORCE ORDER)。 SQL查询优化器中的愚蠢错误会生成一个尝试加入未过滤的varchar和唯一标识符的计划。添加FORCE ORDER会导致它首先运行过滤器。

我知道,重载列很糟糕。有时,你必须忍受它。

答案 4 :(得分:0)

逻辑计划优化器无法向您保证它找到了最佳解决方案:精确算法太慢而无法在生产服务器中使用;而是使用了一些贪婪的算法。

因此,这些命令背后的基本原理是让用户指定最佳连接策略,如果优化器无法找出最适合采用的方法。