我有一台运行 SQL Server Enterprise 2016 SP2 的服务器,我注意到每分钟都有数百个查询计划失效。我运行sp_BlitzCache @expertmode=1
检查“创建于”列以查看计划何时生成。
每分钟大约有 500 个计划被重新创建,并且这种情况会持续一整天,并且总是会重新编译不同的计划。
当我使用 DMVsys.dm_db_index_usage_stats
检查 user_updates 时,我发现索引上发生了 10.000 到 1.000.000 次更新。有些表有超过 10.000.000 条记录,但大多数表有 100.000 到 2.000.000 条记录。
据我所知,查询计划在以下情况下会失效:
- 通过 ALTER TABLE/ALTER VIEW 对表/视图定义所做的修改
- 对执行计划使用的任何索引所做的更改
- 更新执行计划使用的统计信息(手动或自动)
- 删除查询计划使用的索引
- sp_recompile / 重新编译
- 表的大量更改
- 在执行计划使用的表上添加/删除触发器
- 内存压力
所有查询都使用KEEP PLAN
and KEEPFIXED PLAN
,所以我认为自动或手动更新统计信息不会使计划无效。这是第三方应用程序,因此我无法更改查询。当我运行时,UPDATE STATISTICS [TableTest] WITH FULLSCAN
我没有看到使用该表的查询的重新编译。
接下来,我使用了Jonathan Kehayias 的脚本来检查是否存在内存压力,但脚本只返回了RESOURCE_MEMPHYSICAL_HIGH
,所以我认为这不是问题所在。
没有修改表定义,没有发生索引,也没有使用 sp_recompile / with recompile 执行查询
是否还有其他原因会导致查询计划失效?
更新:
经过更多研究后,我认为重新编译是由 plancache 上的内存压力触发的。本文提供了大量有关计划缓存内部结构的信息。这是关于 SQL Server 2005 但希望这仍然适用于 SQL Server 2016。
根据这篇文章,您可以根据可见目标内存总量计算压力限制。
我的研究进展缓慢,因为很难找到有关计划缓存压力的信息。
我会及时通知您进展情况
经过一些扩展研究,我找到了问题的原因。因此,SQL Server 计算缓存压力限制使用以下公式:
自 SQL Server 2012 及更高版本以来,当缓存存储增长到计划缓存压力限制的 62.5% 时,会触发内存压力。发生这种情况时,将使用基于计划成本的称为逐出策略的算法从缓存中删除计划。
所以在某些时候,我会看到我的计划缓存大小下降,这种情况一天会发生好几次,导致每次都编译新计划。