带重新编译的存储过程

seb*_*eid 6 performance sql-server optimization execution-plan query-performance

我有这个存储过程..当我告诉开发人员不推荐使用 Recompile 选项时,他们回答说“这是因为可以使用许多不同的参数调用这个 SP,我们希望优化器获取一个新计划每次调用(不理想,但与使用旧的缓存计划相比,这是一次尝试让它运行得更可靠、速度更快)”

他们说的对吗?有什么方法可以不用重新编译就可以做到这一点

   create PROCEDURE [dbo].[VERIFIER_QUEUE]
   @cas_name varchar(20) = NULL,
   @instance_name varchar(50) = NULL,
   @verifier_id int = NULL,
   @applicant_type VARCHAR(20) = NULL

    WITH RECOMPILE     
    AS

   BEGIN 
SET NOCOUNT ON

DECLARE @cas_name_x varchar(20)
DECLARE @instance_name_x varchar(50)
DECLARE @verifier_id_x int
DECLARE @InstanceId INT
...............
Run Code Online (Sandbox Code Playgroud)

Aar*_*and 7

Michael Green 是对的:开发人员正试图阻止参数嗅探,当 SQL Server 编译一个对一组参数值很好但对其他参数值很糟糕的计划时,就会发生这种情况。

您需要OPTION (RECOMPILE)在有问题的语句上使用,而不是WITH RECOMPILE在程序上使用。而且我不会推荐局部变量“技巧”——它只会让代码更混乱;OPTIMIZE FOR UNKNOWN如果这是在您的场景中最有效的方法,那么最好在现代版本上使用。(有关此主题的更多信息,请参阅Paul White 的这篇很棒的帖子。)

此外,如果许多参数是可选的(所以查询有类似的东西WHERE col = @param or @param IS NULL),这就是我所说的“厨房水槽”——有时动态 SQL 可能是一个更有效的解决方案。你没有展示你的其余代码,只是你已经在使用局部变量技巧,但它基本上看起来像这样:

DECLARE @sql NVARCHAR(MAX) = N'SELECT ... FROM ... WHERE 1 = 1';

IF @cas_name IS NOT NULL
  SET @sql += N' AND cas_name = @cas_name';

IF @instance_name IS NOT NULL
  SET @sql += N' AND instance_name = @instance_name';

IF @verified_id IS NOT NULL
  SET @sql += N' AND verifier_id = @verifier_id';

...

SET @sql = @sql + N' OPTION (RECOMPILE);';
PRINT @sql;

EXEC sys.sp_executesql @sql,
  N'@cas_name VARCHAR(20), @instance_name VARCHAR(50), @verifier_id INT, ...',
  @cas_name, @instance_name, @verifier_id, ...;
Run Code Online (Sandbox Code Playgroud)

这种只为实际提供的参数添加子句的方法可以保护您免受基于不同参数集的缓存计划的影响(例如,如果我@FirstName在第一次执行时提供,则缓存的该列上的查找计划在以下情况下将无济于事我要求@LastName LIKE N'%s%')。的OPTION (RECOMPILE);由能够变化在很大程度上取决于计划在端部保护你从执行相同的参数执行的(例如,WHERE name LIKE N'%s%'应当产生比不同的平面形状WHERE name LIKE N'Q%')。

这通常最适用于服务器设置optimize for ad hoc workloads,您可以在此处此处阅读有关内容。本质上,这样做是为了防止您的计划缓存被所有这些轻微的计划变化填满,除非它们被多次使用。(是的,使用OPTION (RECOMPILE),这一点没有实际意义;但是,服务器设置不会对您的其他临时查询工作负载造成伤害,而且我从未遇到过启用它的缺点。)

这对于 SQL 注入非常安全,因为您不必担心将用户输入连接到 SQL 字符串中(所有参数都是强类型的),但是阅读有关动态 SQL 的这些主题不会有什么坏处:

在这里这里有关于我的“厨房水槽”解决方案的视频以及关于它的博客文章

  • @Andomar 当我的轮胎漏气时更换整辆车也没有错。为一个问题语句重新编译整个过程是不雅的、浪费的,并且会失去某些优化(参见 [Paul White 的帖子](http://sqlperformance.com/2013/08/t-sql-queries/parameter-sniffing-embedding-and -the-recompile-options)。)仅仅因为微软的文档将两者相关联并不能使它成为最好的主意。 (2认同)