使用和不使用存储过程调用的不同 SQL 行为
Different SQL behavior with and without a stored procedure call
运行 MS SQL Server 2008,如果我执行以下查询,它运行得相当快(2 秒或更少)和 returns 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 行。知道可能有什么问题以及如何使原始存储过程正常工作吗?
更新
如果我像这样只传递 2 个参数之一
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'
也许是参数嗅探,我该如何解决?
一个存储过程有一个存储的执行计划。使用传递给它的第一个参数创建和优化该计划。如果它是一个可能差异很大的参数,请考虑在 table 值函数中使用选项 (OPTIMIZE FOR (@ValueTime UNKNOWN, @PriceUpdTime UNKNOWN)
)。
更多信息here
您遇到了一个叫做参数嗅探的事情,您会找到很多视频/其他 material。基本上,它的发生是因为 SQL 服务器将根据它获得的参数为过程创建计划,而你的参数是 NULL @PriceUpdTime -- 计划是基于此完成的。
如果对于这种情况,添加 "option (optimize for (@PriceUpdTime unknown))" 将创建具有未知值的计划,而不是 NULL,这对您来说可能是足够好的解决方案。
如果您知道您将获得几种不同类型的日期作为参数,您还可以考虑将 "option (recompile)" 添加到语句中。这样,每次调用过程时都会完成查询计划。它会消耗一些 CPU,但如果你是 table,你正在访问的是巨大的,糟糕的计划可能会导致严重的问题,这可能是值得的。
运行 MS SQL Server 2008,如果我执行以下查询,它运行得相当快(2 秒或更少)和 returns 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 行。知道可能有什么问题以及如何使原始存储过程正常工作吗?
更新 如果我像这样只传递 2 个参数之一
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'
也许是参数嗅探,我该如何解决?
一个存储过程有一个存储的执行计划。使用传递给它的第一个参数创建和优化该计划。如果它是一个可能差异很大的参数,请考虑在 table 值函数中使用选项 (OPTIMIZE FOR (@ValueTime UNKNOWN, @PriceUpdTime UNKNOWN)
)。
更多信息here
您遇到了一个叫做参数嗅探的事情,您会找到很多视频/其他 material。基本上,它的发生是因为 SQL 服务器将根据它获得的参数为过程创建计划,而你的参数是 NULL @PriceUpdTime -- 计划是基于此完成的。
如果对于这种情况,添加 "option (optimize for (@PriceUpdTime unknown))" 将创建具有未知值的计划,而不是 NULL,这对您来说可能是足够好的解决方案。
如果您知道您将获得几种不同类型的日期作为参数,您还可以考虑将 "option (recompile)" 添加到语句中。这样,每次调用过程时都会完成查询计划。它会消耗一些 CPU,但如果你是 table,你正在访问的是巨大的,糟糕的计划可能会导致严重的问题,这可能是值得的。