我可以出于调试目的禁​​用执行计划缓存吗?

Bre*_*ill 7 sql-server execution-plan

我试图在我们的应用程序中隔离性能不佳的查询。

虽然查询执行计划缓存在生产中非常有用,但它会干扰我们的调试工作。

有没有办法临时禁用 SQL Server 中的执行计划缓存(任何进一步),以便我每次运行查询批处理时都能获得可靠和真实的 SQL 解析和编译时间指标?

Eri*_*rik 13

根据文档,有三种方法可以重新编译存储过程和/或存储过程中的查询。

重新编译

这可能是强制重新编译最直接的方法,如果您愿意编辑存储过程的定义,那么您每次都可以自动强制重新编译。但是有一些重要的缺点需要注意。

CREATE PROCEDURE dbo.FooForProfit @Blood INT, @Sweat BIGINT, @Tears SMALLINT
  WITH RECOMPILE
AS
  -- Do that foo-do that you do so well (for profit)!
Run Code Online (Sandbox Code Playgroud)

或者,您可以这样在执行后添加提示:

EXECUTE dbo.FooForFun @Joy = 42 WITH RECOMPILE;
Run Code Online (Sandbox Code Playgroud)

问题:

  • 这会损害性能,并且很可能会给您带来受污染的性能值。
  • 根据您执行存储过程的方式,可能无法WITH RECOMPILEEXECUTE语句之后添加。
  • 编译后的计划不会被缓存,也不会维护性能信息1

    不缓存存储过程的编译计划。因此,在 sys.dm_exec_query_stats 等 DMV 中不会维护任何性能信息。

  • 这将禁用 Parameter Embedding Optimization 1

    参数嵌入优化使这个过程更进一步:在查询解析期间查询参数被替换为文字常量值。解析器能够进行令人惊讶的复杂简化,随后的查询优化可能会进一步完善。

我觉得重要的是要注意一些非常聪明和经验丰富的人,比如Aaron Bertrand,所以不要走这条路。我最初认为这将是您最好的选择,但现在我确信这可能不是理想的解决方案。

SP_RECOMPILE

如果您不能或不想修改存储过程,并且您的数据访问机制不允许您附加查询提示,您可以使用另一个提供的存储过程手动强制重新编译存储过程。这条路线的一个好处是你可以随意强制重新编译,这样你就可以轻松地比较有或没有编译惩罚的执行。

EXEC sp_recompile N'dbo.FooForFame';
Run Code Online (Sandbox Code Playgroud)

问题:

  • 这将在您的过程中添加一个单独的步骤来重置您的测试台。
  • 您可以将其添加到与执行存储过程相关联的触发器中。<-- 不要这样做,因为您不想鼓励疯子或创造更多。

重新编译查询提示

就像它在文档中所说的那样,如果存储过程有多个查询,这将使您对重新编译的内容进行更细粒度的控制。

RECOMPILEWITH RECOMPILE当只需要重新编译存储过程中的查询子集而不是整个存储过程时,这是创建使用子句的存储过程的一种有用的替代方法。RECOMPILE在创建计划指南时也很有用。

它还可以让您重新编译不在存储过程中的语句。出于显而易见的原因,这很有用。这是一个示例:

SELECT
  Peace 
FROM dbo.TheWorld
OPTION (RECOMPILE);
Run Code Online (Sandbox Code Playgroud)

问题:

  • 如果您确实在存储过程中有多个语句,这将稍微多一些工作。


KAS*_*DBA 4

您可以肯定使用 Erik 提到的选项重新编译:

此外,您还可以使用以下命令暂时禁用该特定执行计划的缓存DBCC FREEPROCCACHE(Plan_handle)

您可以从下面找到缓存的计划句柄(针对该查询):

SELECT cp.plan_handle, st.[text]
FROM sys.dm_exec_cached_plans AS cp 
CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS st
WHERE [text] LIKE N'%/* SP_or_Part of query_goes_here %';
Run Code Online (Sandbox Code Playgroud)

或者您可以使用 dmvsys.dm_exec_query_stats然后CROSS APPLY sys.dm_exec_sql_text获取 sql 文本查询。过滤以查找将显示 plan_handle_id 的查询之一

获得后plan_handle,您可以简单地执行:

DBCC FREEPROCCACHE(Plan_handle_id_from_above_goes_here)
Run Code Online (Sandbox Code Playgroud)