在存储过程中临时运行时,代码会创建不同的计划


9

我有一条delete语句,在存储过程中运行时使用了错误的计划,但是在临时运行时选择了更好的计划。

我已经为查询使用的表重建了所有索引,并删除了所有缓存。优化器仍然为存储过程选择了错误的计划。

我想知道为什么优化器对存储过程使用的是与临时SQL不同的执行计划。

更新:我猜想它毕竟一定是参数-当我运行带有硬编码变量的临时代码时,我可以获得具有正确值的“坏”计划(这是一个日期,一个岁的值)似乎会产生“好的”计划)。现在继续尝试通过使用查询提示在proc上强制执行“良好”计划。

解决方案:我最终使用OPTIMIZE FOR UNKNOWN提示获得了想要的计划。


这可能是参数嗅探。查询是否在其WHERE子句中引用变量?
Nick Chammas

4
您能添加代码吗?
gbn

请将计划也张贴在某个地方。照原样,很难确切地告诉您计划为何不同。
亚伦·伯特兰

好的,更多信息:在对计划和代码进行些许混淆之前,我无法发布它们。我会尽力使它们起来。存储过程的计划(错误)对大型表(整个事物,所有分区)进行聚集索引扫描。然后,它使用循环从较小的表中查找行,然后从较小的表中删除。
msgisme 2011年

临时代码(良好)的计划对小型表(仅具有5-10行)进行表扫描,并使用大型表的非聚集索引来查找需要在PK中检查的行大桌子的 我会尽快制定实际计划。
msgisme 2011年

Answers:


5

普通嫌犯:

  1. adhoc中的常量,代码中的参数
  2. 代码中的数据类型不匹配
  3. 参数嗅探

要点1:优化器可以为常数选择最佳方案。
更改常数=更改计划。参数化全包是可恢复的

由于数据类型优先级,第2点将引入隐式转换,
例如varchar列与nvarchar参数相比

第3点:使用参数屏蔽或优化未知
编辑:测试:运行存储的proc,运行sp_updatestats,然后再次运行。这将使缓存的计划无效,这比清除计划缓存更好

编辑:jcolebrand的评论后

您可以通过多种方式禁用嗅探。主要的三个是

  • 推荐。这真是愚蠢的海事组织。
  • 优化(原文如此)未知
  • 参数屏蔽

参数屏蔽:

DECLARE @MaskedParam varchar(10)
SELECT @MaskedParam = @SignaureParam

SELECT...WHERE column = @MaskedParam

屏蔽和OPTIMIZE提示具有相同的效果(可能出于不同的原因)。也就是说,优化器必须使用统计信息和数据分布(请注意:仍由Mark Storey-Smith 进行 测试根据自身的价值评估参数,而不是他们最后一次拨打的电话。优化器可以重新编译或不重新编译。SQL Server 2005添加了语句级别的重新编译,因此影响较小

现在,为什么带有“嗅探”参数的计划与“蒙版” /“未知”参数相比是“粘性”的,我不确定。

从SQL Server 2000开始,除了最简单的代码,我都使用了参数屏蔽。我注意到,使用更复杂的代码很容易发生这种情况。在我的旧工作中,我有一些报告过程,可以更改计划参数的默认值。我认为,“货运崇拜”方法比支持电话要容易。

聊天后,编辑2,2011年10月12日

  • 据我所知
    ,参数掩码和OPTIMIZE FOR UNKNOWN具有相同的效果。提示比掩码更干净,但它是在SQL Server 2008中添加的。

  • 参数嗅探发生在编译时。
    WITH RECOMPILE每次执行都会生成一个新计划。这意味着不良的默认选择会影响计划。在我的上一份工作中,我可以通过一些报告代码轻松地演示这一点:更改参数默认值会更改计划,而不管所提供的参数如何。

  • 这篇MS Connect文章很有趣:存储过程中的次优索引用法(在下面的SO回答之一中提到)

  • Bob Beauchemin也提到了

显着的问题

  • 嗅探是否仍适用于WITH RECOMPILE?也就是说,如果优化师知道放弃计划,那么它是否打算重新使用?

  • 为什么嗅探到的计划“很粘”?

来自SO的链接:


1. sp中的param是代码中的变量2.再次,相同的数据类型3.我都使用各种各样的参数运行,并且每次都得到相同的计划。每次尝试后我都清除了缓存。
msgisme 2011年

1
回复:第3点。您也可以使用OPTION (RECOMPILE)或整个proc 运行语句,WITH RECOMPILE以强制SQL Server忽略现有计划。
Nick Chammas

3
顺便说一句OPTIMIZE,因为微软是一家美国公司。:)
Nick Chammas

1
@Gbn关于防止/击败参数嗅探有什么想法?
jcolebrand

1
@jcolebrand:简单的答案是“不” :-)
GBN

2

不要忘记,为连接计划设置的ANSI设置在执行计划选择中起着重要作用。当应用程序调用存储过程时,它可能具有与SSMS连接不同的ANSI设置。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.