查询计划缓存因临时查询而膨胀,即使使用“优化临时工作负载”

Mar*_*son 7 sql-server execution-plan sql-server-2012 plan-cache

我一直注意到我们的查询计划缓存存在一些我认为不寻常的问题,其中缓存中的计划从未超过一天。

通过运行以下查询(由Kimberly Tripp 提供),它表明大多数计划(4.5Gb 的 6Gb 缓存计划或 44813 的 ~50000)是使用计数为 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
Run Code Online (Sandbox Code Playgroud)

我已经确定了问题查询(动态的EXEC,当然带有......),这相当可怕,但也很复杂,只是“修复”,所以我正在研究可以立即进行的改进。

该实例已设置为使用 Optimize for Ad-hoc Workloads,但是CacheObjTypefromsys.dm_exec_cached_plans都是Compiled Plan而不是Compiled Plan Stub

当使用 Ad-hoc Workload 模式时,计划是否应该在它们大于 1之前不被编译为计划存根usecounts?或者这不是它的工作原理?

refcounts在谈论即席查询时,还有一个似乎没有人提及的领域。所述引用计数始终为1时的类型被编译的计划存根和2当类型是编译的计划。即使通过阅读BOL,我也不完全确定该字段的含义。有人可以澄清吗?

SQL*_*Fox 6

根据,一个特设批次的第二次运行去除存根(其中仅使用一次),并创建和缓存计划(使用它的第一次)。

refcounts除了缓存对象的引用计数之外,我还没有看到很多引用。Adhoc Compiled Plan 对象的 a 仍然可以refcount为 1,因此这不仅仅是由计划的持久性引起的。

  • 来自@SQLFox 提供的链接 - 已编译计划存根允许数据库引擎识别此临时批处理之前已编译但仅存储了已编译计划存根,因此当再次调用(编译或执行)此批处理时,* *数据库引擎编译批处理,从计划缓存中删除已编译的计划存根,并将完整的已编译计划添加到计划缓存中**。 (4认同)