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 RECOMPILE在EXECUTE语句之后添加。不缓存存储过程的编译计划。因此,在 sys.dm_exec_query_stats 等 DMV 中不会维护任何性能信息。
参数嵌入优化使这个过程更进一步:在查询解析期间查询参数被替换为文字常量值。解析器能够进行令人惊讶的复杂简化,随后的查询优化可能会进一步完善。
我觉得重要的是要注意一些非常聪明和经验丰富的人,比如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)
问题:
您可以肯定使用 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)