【问题标题】:How to prevent recompile for ad hoc query如何防止为临时查询重新编译
【发布时间】:2021-12-09 12:21:32
【问题描述】:

当我第一次运行以下查询时,重新编译需要(7 秒)。如果我再次运行它,结果会在

有没有一种方法可以防止重新编译而无需使用 SP(已经验证可以工作)包装它?

set statistics time on;

declare
    @o bigint = 3374707

select * from ComplexTableValuedFunction(@o)
option (keep plan, use hint ('DISABLE_PARAMETER_SNIFFING')) -- has no effect in ad hoc?

set statistics time off;

附带问题:由于某种原因,统计信息只列出了较短的执行时间(~100 毫秒)而不是编译时间。 SQL Sentry 验证编译时间约为 7 秒。

【问题讨论】:

  • 缓存的执行计划是缓存键控于两件事的组合:(1)查询语句的哈希值和(2)当前的@@OPTIONS。由于您通过更改数字(即使只是一个数字)来更改语句的哈希值,因此新语句将需要编译和潜在的缓存。避免(大部分)这种情况的方法是将 select 语句本身放在表值用户定义函数或存储过程中。然后它有自己的计划,你的语句的特别部分将被快速编译并单独缓存。
  • 那么这里的ComplexView是什么,因为参数的关系,它不是实际视图,所以必须已经是TVF了?
  • @stu,是的,它是一个内部加入多个视图的 TVF。

标签: sql-server caching sql-execution-plan


【解决方案1】:

任何时候,即席批更改,即使是单个字符,都会重新编译。

为防止重新编译,您需要使用sp_executesql 传递批处理,并对其进行适当的参数化。此时会得到参数嗅探,除非添加提示'DISABLE_PARAMETER_SNIFFING'

set statistics time on;

EXEC sp_executesql
  N'
select * from ComplexTableValuedFunction(@o);
',
  N'@o bigint',
  @o = 3374707;

set statistics time off;

实际的EXEC 语句没有查询计划,因此更改值不会影响任何事情。

请注意,来自客户端应用程序(例如 C#/SqlClient)的参数化查询实际上无论如何都使用sp_executesql

【讨论】:

  • 如果你想防止参数嗅探,你只需要一个提示,这可能是也可能不是一件好事。请注意,来自客户端应用程序(例如 C#/SqlClient)的参数化查询实际上无论如何都使用sp_executesql
猜你喜欢
  • 1970-01-01
  • 2011-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-17
  • 1970-01-01
相关资源
最近更新 更多