我一直注意到我们的查询计划缓存存在我认为不寻常的问题,缓存中的计划从未超过一天。
通过运行以下查询(由Kimberly Tripp提供),它表明大多数计划(6Gb 缓存计划中的 4.5Gb 或 ~50000 中的 44813 个)是使用计数为 1 的即席查询。
SELECT objtype AS [CacheType]
, count_big(*) AS [Total Plans]
, sum(cast(size_in_bytes as decimal(18,2)))/1024/1024 AS [Total MBs]
, avg(usecounts) AS [Avg Use Count]
, sum(cast((CASE WHEN usecounts = 1 THEN size_in_bytes ELSE 0 END) as decimal(18,2)))/1024/1024 AS [Total MBs - USE Count 1]
, sum(CASE WHEN usecounts = 1 THEN 1 ELSE 0 END) AS [Total Plans - USE Count 1]
FROM sys.dm_exec_cached_plans
GROUP BY objtype
ORDER BY [Total MBs - USE Count 1] DESC
我已经确定了问题查询(动态的EXEC
,当然带有 ......),这相当可怕,但“修复”也很复杂,所以我正在研究可以立即做出的改进。
该实例已设置为使用 Optimize for Ad-hoc Workloads,但是CacheObjType
fromsys.dm_exec_cached_plans
都是Compiled Plan而不是Compiled Plan Stub。
使用 Ad-hoc Workload 模式时,计划是否应该在它们大于 1之前不被编译计划存根?usecounts
或者这不是它的工作原理?
在谈论 Adhoc 查询时,还有refcounts
一个似乎没有人提及的领域。当类型为Compiled Plan Stub时,refcounts 始终为 1,当类型为Compiled Plan 时,refcounts 始终为2 。即使通过阅读BOL,我也不完全确定该字段的含义。有人可以澄清吗?
据此,即席批处理的第二次运行删除了存根(仅使用过一次)并创建并缓存了计划(第一次使用它)。
refcounts
除了缓存对象的引用计数之外,我还没有看到很多引用。Adhoc Compiled Plan 对象的 a 仍然可以refcount
为 1,因此它不完全是由计划的持久性引起的。