table 值参数的参数嗅探
Parameter sniffing on table valued parameters
我相当确定将参数嗅探添加到 table 有价值的参数几乎没有或没有价值但是我想知道是否有人可以证实这一点?
(INT_LIST 是用户定义的 table 类型,它是 INT 类型的单列)
CREATE PROCEDURE [dbo].[TVPSniffTest](
@param1 varchar(50),
@idList INT_LIST readonly
)
AS
BEGIN
DECLARE @param1_sniff VARCHAR(50) = @param1 --this is worth doing
DECLARE @idList_sniff INT_LIST
INSERT INTO @idList_sniff SELECT value FROM @idList --will this help?
--query code here
END
这没有任何效果 -- 事实上,它对性能有害,因为您首先复制了整个 table。
优化器不维护 table 值参数或 table 变量的统计信息。这很容易导致基数不匹配的糟糕查询计划;解决方案通常是中间温度 table。在任何情况下,参数嗅探都不是问题——table 内容从未用于优化查询计划。
顺便说一句,虽然您可以将参数分配给局部变量以规避嗅探,但更灵活的选择是在特别受影响的查询中使用 OPTIMIZE FOR
or RECOMPILE
提示(或 WITH RECOMPILE
整个存储过程,但这有点激烈)。这可以防止所有内容的副本使程序混乱。
正如 Jeroen 已经提到的,TVP 不存在参数嗅探问题。还有一种减轻统计数据不足的方法是将 TVP 复制到本地临时文件 table(它确实维护统计数据)。
但是,有时更有效的另一种选择是使用 table 变量(即 TVP)对任何查询进行语句级重新编译。统计信息不会跨查询维护,因此需要在涉及 table 变量的任何查询上完成,该变量不像简单的 SELECT.
以下说明了此行为:
DECLARE @TableVariable TABLE (Col1 INT NOT NULL);
INSERT INTO @TableVariable (Col1)
SELECT so.[object_id]
FROM [master].[sys].[objects] so;
-- Control-M to turn on "Include Actual Execution Plan".
-- For each of the 3 following queries, hover over the "Table Scan"
-- operator to see the "Estimated Number of Rows".
SELECT * FROM @TableVariable; -- Estimated Number of Rows = 1 (incorrect)
SELECT * FROM @TableVariable
OPTION (RECOMPILE); -- Estimated Number of Rows = 91 (correct)
SELECT * FROM @TableVariable; -- Estimated Number of Rows = 1 (back to incorrect)
我相当确定将参数嗅探添加到 table 有价值的参数几乎没有或没有价值但是我想知道是否有人可以证实这一点?
(INT_LIST 是用户定义的 table 类型,它是 INT 类型的单列)
CREATE PROCEDURE [dbo].[TVPSniffTest](
@param1 varchar(50),
@idList INT_LIST readonly
)
AS
BEGIN
DECLARE @param1_sniff VARCHAR(50) = @param1 --this is worth doing
DECLARE @idList_sniff INT_LIST
INSERT INTO @idList_sniff SELECT value FROM @idList --will this help?
--query code here
END
这没有任何效果 -- 事实上,它对性能有害,因为您首先复制了整个 table。
优化器不维护 table 值参数或 table 变量的统计信息。这很容易导致基数不匹配的糟糕查询计划;解决方案通常是中间温度 table。在任何情况下,参数嗅探都不是问题——table 内容从未用于优化查询计划。
顺便说一句,虽然您可以将参数分配给局部变量以规避嗅探,但更灵活的选择是在特别受影响的查询中使用 OPTIMIZE FOR
or RECOMPILE
提示(或 WITH RECOMPILE
整个存储过程,但这有点激烈)。这可以防止所有内容的副本使程序混乱。
正如 Jeroen 已经提到的,TVP 不存在参数嗅探问题。还有一种减轻统计数据不足的方法是将 TVP 复制到本地临时文件 table(它确实维护统计数据)。
但是,有时更有效的另一种选择是使用 table 变量(即 TVP)对任何查询进行语句级重新编译。统计信息不会跨查询维护,因此需要在涉及 table 变量的任何查询上完成,该变量不像简单的 SELECT.
以下说明了此行为:
DECLARE @TableVariable TABLE (Col1 INT NOT NULL);
INSERT INTO @TableVariable (Col1)
SELECT so.[object_id]
FROM [master].[sys].[objects] so;
-- Control-M to turn on "Include Actual Execution Plan".
-- For each of the 3 following queries, hover over the "Table Scan"
-- operator to see the "Estimated Number of Rows".
SELECT * FROM @TableVariable; -- Estimated Number of Rows = 1 (incorrect)
SELECT * FROM @TableVariable
OPTION (RECOMPILE); -- Estimated Number of Rows = 91 (correct)
SELECT * FROM @TableVariable; -- Estimated Number of Rows = 1 (back to incorrect)