1

运行 MS SQL Server 2008,如果我执行以下查询,它会运行得非常快(2 秒或更短)并返回 906 行:

DECLARE @ValueTime    datetime2
DECLARE @PriceUpdTime datetime2
SELECT  @ValueTime = '2014-11-28 23:00:00.000000'
SELECT  @PriceUpdTime = CURRENT_TIMESTAMP
SELECT  *
  FROM dbo.fMyTableFunction(@PriceUpdTime, @ValueTime) AS prices

但是,当我将此代码移动到存储过程中时:

CREATE PROCEDURE dbo.MDMTmp
(
    @ValueTime    datetime2 = NULL,
    @PriceUpdTime datetime2 = NULL
)
AS
BEGIN
    SET NOCOUNT ON;

    IF @PriceUpdTime IS NULL
        SELECT @PriceUpdTime = CURRENT_TIMESTAMP

    SELECT *
      FROM dbo.fMyTableFunction(@PriceUpdTime, @ValueTime) AS prices
END

通话

EXEC dbo.MDMTmp '2014-11-28 23:00:00.000000', NULL

运行速度慢得多(需要永远 - 我在 30 分钟后停止等待)。

在试验时,我只是将不带参数的代码放入这样的存储过程中

CREATE PROCEDURE dbo.MDMTmpVars AS
BEGIN
    DECLARE @ValueTime    datetime2
    DECLARE @PriceUpdTime datetime2

    SELECT  @ValueTime = '2014-11-28 23:00:00.000000'
    SELECT  @PriceUpdTime = CURRENT_TIMESTAMP

    SELECT  *
      FROM dbo.fMyTableFunction(@PriceUpdTime, @ValueTime) AS prices
END

然后执行

EXEC dbo.MDMTmpVars

这就像一个魅力 - 在 1 秒内相同的 906 行。知道可能出了什么问题以及如何使原始存储过程工作吗?

更新 如果我只传递这样的两个参数之一

ALTER PROCEDURE dbo.MDMTmp
(
    @ValueTime    datetime2 = NULL
)
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @PriceUpdTime datetime2
    SELECT  @PriceUpdTime = CURRENT_TIMESTAMP

    IF @PriceUpdTime IS NULL
        SELECT @PriceUpdTime = CURRENT_TIMESTAMP

    SELECT *
      FROM dbo.fBondTickerValueAtRunValueDTs(@PriceUpdTime, @ValueTime) AS prices
END

然后执行

EXEC dbo.MDMTmp '2014-11-28 23:00:00.000000'

它工作正常,但如果我PriceUpdTime改为创建一个参数,它不起作用,无论是我传递NULL还是今天的日期作为字符串。

更新 2 这也是有效的:

ALTER PROCEDURE dbo.MDMTmp
(
    @ValueTimeIn    datetime2 = NULL,
    @PriceUpdTimeIn datetime2 = NULL
)
AS
BEGIN
    SET NOCOUNT ON;

    IF @PriceUpdTimeIn IS NULL
        SELECT @PriceUpdTimeIn = CURRENT_TIMESTAMP

    DECLARE @ValueTime    datetime2
    DECLARE @PriceUpdTime datetime2
    SELECT  @ValueTime    = @ValueTimeIn
    SELECT  @PriceUpdTime = @PriceUpdTimeIn

    SELECT *
      FROM dbo.fBondTickerValueAtRunValueDTs(@PriceUpdTime, @ValueTime) AS prices
END

然后执行任何一个

EXEC dbo.MDMTmp '2014-11-28 23:00:00.000000', NULL
EXEC dbo.MDMTmp '2014-11-28 23:00:00.000000', '2015-02-10'

所以也许是参数嗅探,我该如何解决?

4

2 回答 2

1

存储过程具有存储的执行计划。该计划是使用传递给它的第一个参数创建和优化的。如果它是一个差异很大的参数,请考虑OPTIMIZE FOR (@ValueTime UNKNOWN, @PriceUpdTime UNKNOWN)在表值函数中使用选项 ( )。

更多信息在这里

于 2015-02-10T17:32:01.297 回答
1

你遇到了一个叫做参数嗅探的东西,你会发现很多视频/其他材料。基本上,这是因为 SQL Server 将根据它获得的参数为过程创建计划,而您的参数是 NULL @PriceUpdTime ——并且计划是基于此完成的。

如果在这种情况下,添加“选项(优化(@PriceUpdTime 未知))”将创建具有未知值的计划,而不是 NULL,这对您来说可能是足够好的解决方案。

如果您知道您将获得几种不同类型的日期作为参数,您还可以考虑在语句中添加“选项(重新编译)”。这样,每次调用过程时都会完成查询计划。它会消耗一些 CPU,但是如果您正在访问的表是巨大的,那么糟糕的计划可能会导致严重的问题,这可能是值得的。

于 2015-02-10T17:34:09.810 回答