4

我相当肯定,添加参数嗅探表值参数是很少或没有价值,但我想知道如果有人可以证实这一点?参数嗅探表值参数

(INT_LIST是用户定义的表类型是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 

回答

4

这样做没有任何作用 - 事实上,这是因为你复制整个表的损害性能第一。

优化器不维护表值参数或表变量的统计信息。这很容易导致基数不匹配的错误查询计划;该解决方案通常是一个中间临时表。在任何情况下,参数嗅探都不会成为问题 - 表格内容永远不会用于优化查询计划。顺便说一下,虽然您可以将参数分配给本地变量以规避嗅探,但更灵活的选项是在受到特别影响的查询中使用OPTIMIZE FOR or RECOMPILE提示(或整个存储过程中的WITH RECOMPILE,但稍微多一点激烈)。这可以防止将所有事情的副本混淆在一起。

+2

良好的信息。我意识到你在整个过程中使用'WITH RECOMPILE'确实具有资格,但这应该稍微强调一点,因为这样做的过程称为A LOT(即每分钟多次或更多次)将显示明显性能下降。仍然是+1。 – 2015-02-24 15:53:17

4

正如Jeroen已经提到的,TVPs没有参数嗅探问题。此外,减轻统计数据缺乏的一个选择是将TVP复制到本地临时表(它确实保持统计)。

但是,有时更有效的另一种选择是对使用表变量(即TVP)的任何查询执行语句级重新编译。统计信息将不会在所有查询中维护,因此需要在涉及表变量的任何查询上完成,而该变量不像简单的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) 
+1

另一个很好的答案 - 谢谢! – 2015-02-24 15:26:23

+0

这是一个不错的附录,因为这个文档并不是特定的,OPTION(RECOMPILE)突然让优化器考虑表的基数。它所说的是查询计划“使用查询中任何局部变量的当前值”,但我不会从中推断出它突然开始计算行数。 – 2015-02-24 15:45:57

+0

@JeroenMostert是的,这是我在本地用户组会议中挑选的一个小技巧。我也被告知,在使用表变量的查询中使用'TOP(row_count)'将使用正确的行数,但是我还没有能够证明这一点,所以我没有在这里包括它。 – 2015-02-24 15:56:41