我正在维护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
此查询通过声明和设置新变量来避免参数嗅探。这真的是SQL Server 2005解决OPTIMIZE-FOR-UNKNOWN功能的问题吗?或者我错过了什么? (感谢权威链接,答案或测试结果。)
更多信息: 对SQL Server 2008的快速测试告诉我,此查询中的估计行数实际上与指定了OPTIMIZE FOR UNKNOWN相同。这是SQL Server 2005上的相同行为吗?我想我曾经记得听过一次没有更多信息,SQL Server优化引擎必须猜测参数的选择性(对于不等式谓词,通常为10%)。我仍然在寻找有关SQL 2005行为的确切信息。我不太确定信息是否存在......
更多信息2: 要清楚,这个问题是要求比较UNKNOWN查询提示和我描述的参数屏蔽技术。
这是一个技术问题,而不是解决问题的问题。我考虑了很多其他选择,并坚持这一点。因此,这个问题的唯一目标是帮助我获得两种方法相同的信心。
答案 0 :(得分:4)
我最近几次使用该解决方案来避免SQL 2005上的参数嗅探,在我看来,它与SQL 2008上的OPTIMIZE FOR UNKNOWN做同样的事情。它修复了我们对一些更大的问题的许多问题存储过程有时只是在传递某些参数时挂起。
答案 1 :(得分:4)
好的,所以我做了一些实验。我会在这里写下结果,但首先我要说的是根据我所看到和知道的情况,我相信在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时计划的样子
答案 2 :(得分:1)
有趣的问题。
SQL编程和API开发团队博客here上有一篇很好的文章,其中列出了解决方案解决方案,在SQL 2008之前为:
这引出了我的this文章,其中提到了使用本地参数以及如何根据统计信息生成执行计划的解决方法。我不知道这个过程与新的OPTIMIZER FOR UNKNOWN提示有多相似。我的预感是合理的解决方法。
答案 3 :(得分:0)
至少在过去的一年里我一直在使用这种参数屏蔽技术,因为它出现了奇怪的性能问题,并且运行良好,但是必须一直都很烦人。
我 ALSO 一直使用WITH RECOMPILE
。
我没有受控测试,因为我不能在系统中自动选择性地打开和关闭每个的使用,但我怀疑参数屏蔽只会帮助 IF 使用该参数。我有一些复杂的SP,其中参数没有在每个语句中使用,我希望WITH RECOMPILE
仍然是必要的,因为一些“临时”工作表没有填充(甚至索引相同,如果我正在尝试在每次运行时以相同的方式调整,并且一旦工作表已经适当填充,一些后面的语句就不依赖于参数。我已经将一些流程精确地分解为多个SP,以便可以在下一个SP中针对WITH RECOMPILE
正确分析和执行在一个SP中填充工作表所做的工作。