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

2 回答 2

5

正如 Jeroen 已经提到的,TVP 没有参数嗅探问题。此外,减轻统计数据不足的一种选择是将 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)
于 2015-02-24T15:18:15.513 回答
4

这没有任何影响——事实上,它对性能有害,因为您首先复制了整个表。

优化器不维护表值参数或表变量的统计信息。这很容易导致基数不匹配的错误查询计划;解决方案通常是一个中间临时表。在任何情况下,参数嗅探都不会成为问题——表内容永远不会用于优化查询计划。

顺便说一句,虽然您可以将参数分配给局部变量以规避嗅探,但更灵活的选择是在特别受影响的查询中使用OPTIMIZE FORorRECOMPILE提示(或WITH RECOMPILE在整个存储过程中,但这有点激烈)。这样可以防止程序因所有内容的副本而混乱。

于 2015-02-24T12:53:10.057 回答