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


33

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

该查询通常在几毫秒内运行,但是对于这个错误的查询计划,它需要30秒钟以上的时间。

如何从SQL Server 2008 中仅删除一个不良的缓存查询计划,而又不浪费生产数据库服务器上的整个查询缓存?


看看
-Glenn Berry-

Answers:


39

我弄明白了几件事

select * from sys.dm_exec_query_stats

将显示所有缓存的查询计划。不幸的是,那里没有显示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

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

DBCC FREEPROCCACHE (plan_handle_id_goes_here)

从查询计划缓存中删除每个查询计划。并非完全简单或方便,但它似乎可以工作。

编辑:至少以我的经验,转储整个查询缓存也可以,并且比听起来听起来危险的少。

DBCC FREESYSTEMCACHE ('ALL') WITH MARK_IN_USE_FOR_REMOVAL;

2
使用计划提示的建议仍然有效。
雷木斯·鲁萨努

1
在我的查询神奇地刷新了它的错误计划后,我发现了这一点,但我计划下次进行测试。如果查询遭受“ optional-itis”困扰,则计划提示无济于事-该查询具有许多可选参数,并且已针对一组优化,然后针对另一组运行。对于这种查询,没有可以附加的最佳计划。对于一组参数有一个最佳计划,而对于另一组参数却是糟糕的。
Nick.McDermaid

6

如果您知道好的计划是什么样子,请使用计划提示

您无法删除特定的缓存条目,但是可以使用清理整个缓存池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

但是,所有SQL计划的名称都为“ SQL计划”,这使得为DBCC FREESYSTEMCACHE选择正确的计划变得非常困难。

更新资料

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


1
到plan_handle传给DBCC FREEPROCCACHE的能力,在SQL Server可用2008,而不是在SQL Server 2005
马里奥

如果sys.dm_exec_cached_plans没有plan_handle来自from的条目,那意味着什么sys.dm_exec_requests
乔纳森·吉尔伯特

@JonathanGilbert表示该计划未缓存,或者已从缓存中逐出。见docs.microsoft.com/en-us/sql/relational-databases/...
莱姆斯Rusanu

因此,只是确认一下,即使我只是刚刚开始运行该查询,并且该查询没有提示不缓存它的提示,也可以将其取消缓存,因为SQL Server决定不缓存它吗?不是因为它还在运行,对吧?如果它决定缓存计划,那么它将从查询开始运行的那一刻开始缓存?
乔纳森·吉尔伯特

1

FREEPROCCACHE解决方案是好的,但这样做的更直接的方式是使用OPTION(RECOMPILE)在您的SQL字符串(你提到这不是一个SP),这告诉引擎它的单次使用计划,因为可能你怀疑有参数嗅探,或者您的统计信息在每次运行中都大不相同,因此您怀疑它存在错误的缓存计划问题。

DECLARE @SQL NVARCHAR(4000)
SELECT @SQL = 'SELECT * FROM Table WHERE Column LIKE @NAME OPTION (RECOMPILE)'
EXEC sp_executesql @SQL, N'@NAME varchar(15)', 'MyName' 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.