11

我有一个存储过程,它接受一个日期输入,如果没有传入任何值,则稍后将其设置为当前日期:

CREATE PROCEDURE MyProc
    @MyDate DATETIME = NULL
AS
    IF @MyDate IS NULL SET @MyDate = CURRENT_TIMESTAMP
    -- Do Something using @MyDate

我遇到了问题,如果在首次编译存储过程时@MyDate传入,NULL则所有输入值(或其他)的性能总是很糟糕NULL,如果在编译存储过程时传入日期/当前日期所有输入值(NULL或其他)的性能都很好。

同样令人困惑的是,即使 @MyDate 使用的值实际上是 NULL(而不是CURRENT_TIMESTAMP由 IF 语句设置),生成的糟糕的执行计划也很糟糕

我发现禁用参数嗅探(通过欺骗参数)可以解决我的问题:

CREATE PROCEDURE MyProc
    @MyDate DATETIME = NULL
AS
    DECLARE @MyDate_Copy DATETIME
    SET @MyDate_Copy = @MyDate
    IF @MyDate_Copy IS NULL SET @MyDate_Copy = CURRENT_TIMESTAMP
    -- Do Something using @MyDate_Copy

我知道这与参数嗅探有关,但是我看到的所有“参数嗅探变坏”的示例都涉及使用传入的非代表性参数编译存储过程,但是在这里我看到了执行计划对于 SQL 服务器可能认为参数可能在执行语句的点可能采用的所有可能的值是可怕的 -NULLCURRENT_TIMESTAMP其他。

有没有人知道为什么会这样?

4

3 回答 3

8

基本上是的 - SQL Server 2005 的参数嗅探(在某些补丁级别)被严重破坏。我见过的计划实际上永远不会完成(在一个小数据集上的几个小时内),即使对于小(几千行)数据集,一旦参数被屏蔽,这些数据集在几秒钟内完成。这是在参数始终为相同数字的情况下。我要补充一点,在我处理这个问题的同时,我发现了很多关于 LEFT JOIN/NULLs 没有完成的问题,我用 NOT IN 或 NOT EXISTS 替换了它们,这解决了计划到一些可以完成的事情。同样,一个(非常糟糕的)执行计划问题。在我处理这个问题的时候,DBA 不会给我 SHOWPLAN 访问权限,因为我开始屏蔽每个 SP 参数,所以我'

在 SQL Server 2008 中,您可以使用OPTIMIZE FOR UNKNOWN.

于 2009-06-17T14:40:33.557 回答
1

我能够在(SQL Server 2005)中解决这个问题的一种方法是添加查询优化器提示,而不是仅仅通过重新声明本地参数来屏蔽参数。

这是一篇很好的博客文章,详细讨论了它: SqlServer 2005 中的参数嗅探

我用过: OPTION (优化 (@p = '-1'))

于 2009-09-25T23:09:08.973 回答
0

在过程内部声明过程参数,并将外部参数传递给内部..编译..

于 2019-07-16T13:04:26.253 回答