【问题标题】:Is this query equivalent to SQL Server 2008's OPTIMIZE FOR UNKNOWN?此查询是否等同于 SQL Server 2008 的 OPTIMIZE FOR UNKNOWN?
【发布时间】:2010-02-08 22:21:29
【问题描述】:

我正在维护 SQL Server 2005 的存储过程,我希望我可以在 2008 年使用允许查询提示的新功能:“OPTIMIZE FOR UNKNOWN”

似乎以下查询(为 SQL Server 2005 编写)估计的行数(即选择性)与指定了 OPTION (OPTIMIZE FOR UNKNOWN) 一样:

CREATE PROCEDURE SwartTest(@productid INT)
AS  
DECLARE @newproductid INT
SET @newproductid = @productid

SELECT ProductID 
FROM Sales.SalesOrderDetail 
WHERE ProductID = @newproductid

此查询通过声明和设置新变量来避免参数嗅探。这真的是针对 OPTIMIZE-FOR-UNKNOWN 功能的 SQL Server 2005 解决方法吗?还是我错过了什么? (感谢权威链接、答案或测试结果)。

更多信息: 对 SQL Server 2008 的快速测试告诉我,此查询中估计的行数实际上与指定 OPTIMIZE FOR UNKNOWN 相同。这与 SQL Server 2005 上的行为相同吗?我想我记得曾经听说过没有更多信息,SQL Server 优化引擎必须猜测参数的选​​择性(对于不等式谓词,通常为 10%)。不过,我仍在寻找有关 SQL 2005 行为的明确信息。我不太确定信息是否存在......

更多信息 2: 需要明确的是,这个问题要求比较 UNKNOWN 查询提示和我描述的参数屏蔽技术。

这是一个技术问题,而不是解决问题的问题。我考虑了很多其他选择并最终决定了这一点。所以这个问题的唯一目的是帮助我获得一些信心,这两种方法是等效的。

【问题讨论】:

标签: sql-server sql-server-2005


【解决方案1】:

我最近多次使用该解决方案来避免 SQL 2005 上的参数嗅探,在我看来,它与 SQL 2008 上的 OPTIMIZE FOR UNKNOWN 做同样的事情。它解决了我们在一些更大的问题上遇到的很多问题存储过程有时只是在传递某些参数时挂起。

【讨论】:

  • 这令人鼓舞。这对我来说似乎也是一样的。我想知道是否有办法确定。
【解决方案2】:

好的,所以我做了一些实验。我会在这里写出结果,但首先我想说的是,根据我所见所闻,我有信心在 2005 年和 2008 年使用临时参数完全正确相当于使用 2008 年的 OPTIMIZE FOR UNKNOWN。至少在存储过程的上下文中。

这就是我发现的。 在上述过程中,我使用的是 AdventureWorks 数据库。 (但我使用类似的方法并为任何其他数据库获得类似的结果)我跑了:

dbcc show_statistics ('Sales.SalesOrderDetail', IX_SalesOrderDetail_ProductID) 

我在直方图中看到了 200 步的统计数据。查看它的直方图,我看到有 66 个不同的范围行(即 66 个不同的值未包含在统计数据中作为相等值)。添加 200 个相等行(来自每个步骤),我估计 Sales.SalesOrderDetail 中 ProductId 有 266 个不同的值。

表中有 121317 行,我可以估计每个 ProductId 平均有 456 行。当我查看我的测试过程的查询计划(xml 格式)时,我看到类似:

...
<QueryPlan DegreeOfParallelism="1"  >
  <RelOp NodeId="0" 
         PhysicalOp="Index Seek" 
         LogicalOp="Index Seek" 
         EstimateRows="456.079" 
         TableCardinality="121317"  />
    ...
  <ParameterList>
    <ColumnReference 
      Column="@newproductid" 
      ParameterRuntimeValue="(999)" />
  </ParameterList>
</QueryPlan>
...       

所以我知道 EstimateRows 值的来源(精确到小数点后三位),并注意到查询计划中缺少 ParameterCompiledValue 属性。这正是使用 2008 年的 OPTIMIZE FOR UNKNOWN 时的计划的样子

【讨论】:

    【解决方案3】:

    有趣的问题。

    在 SQL 编程和 API 开发团队博客 here 上有一篇很好的文章,其中列出了变通解决方案,SQL 2008 之前的版本为:

    1. 使用 RECOMPILE 提示,以便每次都重新编译查询
    2. 取消参数化查询
    3. 在 OPTIMIZE FOR 提示中给出具体值
    4. 强制使用特定索引
    5. 使用计划指南

    这将我引向this 文章,其中提到了您使用本地参数的解决方法以及它如何根据统计数据生成执行计划。这个过程与新的 OPTIMIZER FOR UNKNOWN 提示有多相似,我不知道。我的直觉是这是一个合理的解决方法。

    【讨论】:

    • 我也有同样的预感。而你的“我不知道”是我要问的问题......但感谢您抽出宝贵时间回复。
    【解决方案4】:

    至少在过去的一年里,我一直在使用这种参数屏蔽技术,因为它解决了奇怪的性能问题,而且效果很好,但是不得不一直这样做很烦人。

    ALSO一直在使用WITH RECOMPILE

    我没有控制测试,因为我无法在系统中选择性地自动打开和关闭每个的使用,但我怀疑参数屏蔽只会帮助 IF 使用参数.我有一些复杂的 SP,其中每个语句中都没有使用参数,我希望 WITH RECOMPILE 仍然是必要的,因为一些“临时”工作表没有填充(或者甚至索引相同,如果我试图调整) 每次运行都以相同的方式运行,并且一旦工作表已经适当填充,一些后续语句就不再依赖参数。我已经将一些进程精确地分解为多个 SP,以便在一个 SP 中填充工作表所做的工作可以在下一个 SP 中针对 WITH RECOMPILE 进行正确分析和执行。

    【讨论】:

    • AdaTheDev 建议使用 RECOMPILE 提示。由于我的特殊情况(高容量,大存储空间等),我决定反对它。但是感谢您的技术,很高兴知道。我会把它放进我的心理工具箱里。
    猜你喜欢
    • 2021-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-20
    • 1970-01-01
    • 2011-11-20
    • 1970-01-01
    • 2010-12-17
    相关资源
    最近更新 更多