如何从 SQL Server 查询缓存中删除特定的错误计划?

Jef*_*ood 38 cache query sql-server sql-server-2008

我们有一个特定的 SQL Server 2008 查询(不是存储过程,而是相同的 SQL 字符串——每 5 分钟执行一次),它间歇性地缓存一个非常糟糕的查询计划。

这个查询通常在几毫秒内运行,但是这个糟糕的查询计划需要 30+ 秒。

如何从 SQL Server 2008 中手术删除一个错误的缓存查询计划,而不破坏生产数据库服务器上的整个查询缓存?

Jef*_*ood 45

我想通了一些事情

select * from sys.dm_exec_query_stats
Run Code Online (Sandbox Code Playgroud)

将显示所有缓存的查询计划。不幸的是,那里没有显示 SQL 文本。

但是,您可以将 SQL 文本加入到计划中,如下所示:

select plan_handle, creation_time, last_execution_time, execution_count, qt.text
FROM 
   sys.dm_exec_query_stats qs
   CROSS APPLY sys.dm_exec_sql_text (qs.[sql_handle]) AS qt
Run Code Online (Sandbox Code Playgroud)

从这里开始添加一个WHERE子句来查找我知道在查询中的 SQL 是非常简单的,然后我可以执行:

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

从查询计划缓存中删除每个查询计划。不是很容易或方便,但它似乎有效..

编辑:转储整个查询缓存也可以工作,并且没有听起来那么危险,至少在我的经验中:

DBCC FREESYSTEMCACHE ('ALL') WITH MARK_IN_USE_FOR_REMOVAL;
Run Code Online (Sandbox Code Playgroud)

  • 使用计划提示的建议仍然有效。 (2认同)
  • 在我的查询神奇地刷新后,我发现了这一点,这是一个糟糕的计划,但我计划下次对其进行测试。如果查询遇到“optional-itis”,计划提示无济于事 - 它有许多可选参数,并且已经针对一组进行了优化,然后针对不同的组运行。对于这种查询,没有可以附加的最佳计划。对于一组参数有一个最佳计划,而对于另一组参数则很糟糕。 (2认同)

Rem*_*anu 7

如果您知道好的计划是什么样的,只需使用计划提示即可

您不能删除特定的缓存条目,但可以使用DBCC FREESYSTEMCACHE(cachename/poolname).

如果您有计划句柄(从sys.dm_exec_requests.plan_handle获取执行期间遇到问题的 session_id,或从sys.dm_exec_query_stats执行后),您可以获得错误查询计划的缓存名称:

select ce.name
from sys.dm_exec_cached_plans cp
join sys.dm_os_memory_cache_entries ce on cp.memory_object_address = ce.memory_object_address
where cp.plan_handle = @bad_plan
Run Code Online (Sandbox Code Playgroud)

然而,所有 SQL 计划都具有名称“SQL 计划”,这使得为 DBCC FREESYSTEMCACHE 选择正确的计划是一个……困难的选择。

更新

没关系,忘记了DBCC FREEPROCCACHE(plan_handle),是的,这会起作用。