Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server SQL Server哈希联接和嵌套循环_Sql Server_Join_Sql Execution Plan - Fatal编程技术网

Sql server SQL Server哈希联接和嵌套循环

Sql server SQL Server哈希联接和嵌套循环,sql-server,join,sql-execution-plan,Sql Server,Join,Sql Execution Plan,我在现有数据库(SQL2008-SQL2012)上开发报告,在这些数据库中,我需要以多种不同的方式收集数据 典型的查询可以如下所示 WITH ThisYearData AS ( SELECT ... ) ,LastYearData AS ( SELECT ... ) ,BudgetData AS ( SELECT ... ) SELECT ... FROM SomeDateTable LEFT JOIN ThisYearData ON ...

我在现有数据库(SQL2008-SQL2012)上开发报告,在这些数据库中,我需要以多种不同的方式收集数据

典型的查询可以如下所示

WITH ThisYearData AS (
    SELECT ...
)
,LastYearData AS (
    SELECT ...
)
,BudgetData AS (
    SELECT ...
)
SELECT ...
FROM SomeDateTable
     LEFT JOIN ThisYearData
         ON ...
     LEFT JOIN BudgetData
     ...
有时CTE相互依赖,典型的查询涉及5-10个CTE

问题是,类似的查询可能需要一秒钟到5分钟的时间才能在一小部分数据上运行

性能低下的主要原因是SQL Server使用嵌套循环而不是哈希联接。在某些情况下,我可以在正确的位置加入一个
散列连接
,使查询速度提高100倍。在其他情况下,我将一个或多个CTE转换为表变量

我知道在哈希连接上选择嵌套循环的原因是基于统计数据估计的行数。 在我的情况下,我没有访问数据库模式的权限,因此无法添加索引或统计信息,但我可以确保更新现有统计信息(并启用自动创建/更新统计信息)

要查找导致减速的嵌套循环,请执行以下操作:

  • 查找具有大量行和执行的节点
  • 沿着路径向上走,直到找到正确的嵌套循环
  • 找出导致嵌套循环的联接,并强制它进行
    哈希联接
  • (这样做容易多了)

    我的问题是:

  • 我是否做了一些根本错误的事情,导致SQL Server几乎总是低估行数(以千为单位的估计和实际行数很常见)
  • 执行计划通常以高百分比显示一些不相关的表扫描,这不是很有帮助。执行计划中的百分比是多少?我可以将其更改为在我的场景中更有用吗

  • 使用WITH肯定会降低性能,至少以我的经验来看,在SQL Server上是这样。在不使用WITH构造的情况下编写查询,看看是否能提高性能(我的钱花在:是)

    如果这一点都不起作用,那么在临时表中构建从CTE或派生表中选择的内容。只有当行数非常小(即10或更少)时,表变量才是最好的。如果您注意到使用CTE/派生表的查询速度太慢,那么临时表(至少根据我的经验)可以提供最佳性能

    执行计划通常显示一些不相关的表扫描,并具有较高的优先级 这不是很有帮助。这个比例是多少 执行计划基于什么?我能把它改成对我的工作更有帮助吗 情景

    添加提示“hash join”的问题是,它也会导致所有其他连接的隐式“强制顺序”

    从这里开始::

    评论

    联接提示在查询的FROM子句中指定。加入提示 在两个表之间实施联接策略。如果连接提示是 为任意两个表指定,查询优化器将自动 对查询中的所有联接表强制联接顺序,基于 关键字的位置


    我认为您应该复制数据库并添加统计信息,以尝试在测试环境中提高性能,并查看会发生什么。如果有帮助,那么您可以与决策者交谈,或者创建数据仓库

    我没有看到任何CTE或表变量的性能问题。如果我只是强制
    HASH-JOIN
    的话,性能是可以接受的(CTE相对于其他解决方案的可读性/可维护性是非常有价值的)@adrianm我只能根据经验说话,也就是SQL 2005和2008。在大型数据集上运行的任何足够复杂的查询,如果不使用临时表重写它,运行速度会更快。当然,如果查询在几秒钟内运行,那么优化它是没有用的。如果它运行了几个小时,那么肯定。这不是理论,而是我从实践中学到的东西。我不能为其他版本或RDMS说话。可读性/可维护性确实不会受到IMO的影响,但这只是我的观点。这只是一个指针,可以让您了解使用CTE/派生表时性能不佳的原因:了解CTE的物化,以及为什么在某些情况下这是必要的。CTE没有具体化,在某些情况下,每次访问时都会重建。他们也没有指数或统计数据。临时表通过设计实现,并且可以具有索引/统计信息。您选择构造查询的内容应该取决于复杂性和行数。处理小行的简单查询不需要优化。如果您使用WITH(至少在我所做的测试中是这样),那么在很多行上进行的大规模复杂查询很可能会发生,使用表变量比使用临时表慢。主要问题是表变量没有统计信息,而临时表有统计信息。表变量只能有主键(或唯一约束),而临时表可以有任意数量的索引。你可以在网上查比较。。。经验法则:使用表变量进行UDF返回,使用临时表进行临时存储/临时数据操作,尤其是使用大型数据集。