选项(重新编译)和选项(快速 n)

sal*_*sal -3 sql-server optimization

我被检查的性能OPTION(RECOMPILE)OPTION(FAST n)及其行为有着惊人的不同。OPTION(FAST n)那么快得多OPTION(RECOMPILE)。难道OPTION(FAST n)?每次都创建新的执行计划?

sep*_*pic 6

这些提示有不同的目的:

OPTION(FAST n) 指定查询针对快速检索第一个 number_rows 进行了优化

它不是为了每次都生成最佳计划而设计的,而是简单地诱导优化器“认为”结果基数小于实际基数。所以这个提示与“参数嗅探”无关,它的目标不同于为给定查询生成最佳计划。

OPTION(RECOMPILE)告诉服务器不要为给定的查询缓存 pan。这意味着同一查询的另一次执行将需要制定一个新的(可能不同的)计划。这用于带参数的查询中以防止出现parameter sniffing问题。这意味着您的查询应该根据提供的参数有不同的计划。例如,当您对某个国家/地区的首都查询 smth 过滤时,您的查询几乎会返回 table 中的所有记录,并且scan在这种情况下您更喜欢 table 。但是当你过滤小城市时,你会得到几行并且更喜欢index seek+ lookup

如果您不使用OPTION(RECOMPILE),则您的参数化查询第一次执行其参数时将“嗅探”并根据此参数值制定计划。具有不同参数的后续执行将始终使用相同的计划,这对您来说可能是不可接受的。因此,在这种情况下,您使用OPTION(RECOMPILE)将导致在每次查询执行时对结果集进行最佳基数估计。

概括。

的使用OPTION(FAST n)通常不会导致最佳计划阐述,并且会引起结果集等于 n 的固定(和错误)基数估计。

使用OPTION(RECOMPILE)一般将导致最佳计划选择,并将在每次查询执行时提供不同的(通常是正确的)基数估计,每次都基于提供的参数值。

更新

此重现显示使用 RECOMPILE 选项的查询如何不缓存其计划:

declare @prod_n nvarchar(255) = N'HJ-1428'

select * /*4042FBFE-6ED4-406E-90F8-73C5EBD3920F*/
from [Production].[Product]
where ProductNumber = @prod_n
option(recompile);


declare @sql nvarchar(4000); 
set @sql =
N'select * /*4042FBFE-6ED4-406E-90F8-73C5EBD3920F*/
from [Production].[Product]
where ProductNumber = @prod_n
option(recompile);'

exec sp_executesql @sql, N'@prod_n nvarchar(255)',@prod_n; 


select *
from sys.dm_exec_query_stats qs
    cross apply sys.dm_exec_sql_text(qs.plan_handle) qt
    cross apply sys.dm_exec_query_plan(qs.plan_handle) qp
where qt.text like '%4042FBFE-6ED4-406E-90F8-73C5EBD3920F%' 
  and qt.text not like '%sys.dm_exec_query_stats%'; -- uncomment this to get the plan for given query that looks for the plan
Run Code Online (Sandbox Code Playgroud)

这里我使用guid来区分我的查询,并且我使用and qt.text not like '%sys.dm_exec_query_stats%'条件排除寻找前两个查询的计划的最后一个查询的计划。

我在查询中同时使用了局部变量和参数,但没有一个将计划放入缓存中。

  • 值得注意的是 OPTION(RECOMPILE) 在 CPU 和编译时间方面的额外开销 - 它不应该添加到每个查询中。 (2认同)
  • 其实你的描述是不正确的。OPTION(RECOMPILE) 告诉优化器不要从缓存中检索现有计划,而是在调用过程或临时 T-SQL 时生成一个新计划。生成的计划仍然添加到缓存中。 (2认同)