Eri*_*art 6 execution-plan sql-server-2008-r2 cache parameter
问题目前影响 C#/.NET、基于 ADO.NET 和 SQL Server 2008 R2 的 DB 访问,但我认为它也适用于其他数据库。
我注意到系统的一些旧模块具有非最佳 SQL 查询,使用多个串联的值字符串而不是参数占位符。他们对表进行轮询,例如每 10 秒一次,以获取在过去几分钟内添加的项目,从而在每次执行时生成新的查询计划。
它们的性能还不错,没有 SQL 注入风险(没有 Web/用户表单),它们很旧,将它们的查询更改为正确的参数化需要做很多工作。我建议做这个改变,但有争论说这会浪费时间,其他事情更重要。
编辑:数据库应该使用大部分参数化查询(所有较新的模块都使用)运行,所以我想避免“优化临时”选项。部分参数化查询无论如何都会创建一个计划。在临时优化模式下运行时是否有缺点,主要是参数化查询?
对我来说,这些旧模块似乎占用了数据库资源的很大一部分,尽管它们很少。随着时间的推移,即使是这种类型的单个模块也会创建数千个查询计划,而所有较新的模块加在一起则更少。
更改这些是否重要,还是我可以将它们保留在它们的状态,仅在当前/未来模块中使用优化/参数化查询?
SQL 是这样的:
select ItemId, ItemName from Items
where ItemType=3 and ItemCreator=1234
and ItemDate >= '2013-11-23 12:30:00'
Run Code Online (Sandbox Code Playgroud)
其中值会有所不同,日期是几分钟之前。在少数情况下,日期已更改为“@startDate”之类的参数,以避免出现格式问题,但 ItemType 和 ItemCreator 值仍然是串联字符串。
在使用 DMV 或 Activity Monitor(最近昂贵的查询 - 计划计数列)监视查询计划时,我注意到其中一些查询在缓存中有 8000 多个等效的查询计划:
select count(*), query_plan_hash
from sys.dm_exec_query_stats
group by query_plan_hash
order by count(*) desc
Run Code Online (Sandbox Code Playgroud)
然后使用 sys.dm_exec_query_plan 上的 CROSS APPLY 选择计划 XML,并通过查询计划哈希选择计划句柄。
编辑/临时结论: 似乎最好让非常旧的应用程序保持原样,即使在创建大量临时查询时也是如此。我最担心的是,大量的一次性临时查询会导致好的、多用途的参数化和准备好的查询计划从缓存中被驱逐。这不会发生,因为当清理完成时,临时计划首先被驱逐,其他计划根据复杂性、使用次数等因素进行评级。因此,无论有多少使用率,参数化查询都可能被保留临时或部分参数化的计划大量涌入。临时优化减少了计划大小(实际上,第一次使用时没有存储真正的计划),但可能会保留更多计划,使用类似的内存(这是正确的吗?)。即使是部分参数化的 SQL(避免本地格式问题的 DateTime 参数)如果不再使用,也会很快被驱逐,即使使用 sp_executesql 发送,这会强制参数化和计划缓存。拥有大量(5000 到 8000+)个等效的即席查询计划并不好,但可能比必须挖掘多年的 C#、C++ 甚至 Visual Studio 6.0 代码来修复查询的危害要小(没有人为此付费,并且这些东西仍在运行而没有可识别的问题)。
“有多糟糕?” 取决于您现在遭受的痛苦程度或未来工作量增加可能遭受的痛苦程度。
计划缓存污染的一个主要问题可能是过多的一次性计划使您的计划缓存膨胀,从而导致缓存使用效率低下。
另一个痛苦点可能是高编译/秒 - 因此在工作量大且活动多的环境中,反复编译会产生相关成本。
您可以在 perfmon (SQL Server Statistics:Compilations/sec) 中看到编译/秒的影响。这看起来像是 CPU 压力。对于您的性能/应用程序,这看起来像是每次运行时等待不必要的编译的查询持续时间增加。
通过从 Glenn Berry 的诊断脚本中借用的这个查询,您可以看到内存膨胀对计划缓存的影响。您的 SQLCP 计划缓存有多大?
SELECT TOP(10) [type] AS [Memory Clerk Type],
SUM(pages_kb)/1024 AS [Memory Usage (MB)]
FROM sys.dm_os_memory_clerks WITH (NOLOCK)
GROUP BY [type]
ORDER BY SUM(pages_kb) DESC OPTION (RECOMPILE);
Run Code Online (Sandbox Code Playgroud)
此外,问题中用于确定计划数量的查询也有帮助。
这是一件好事吗?
在某些情况下这可能是好的,但这种情况很少见。基本上,如果您正在遭受参数嗅探变坏的困扰(简而言之:如果数据在基于参数的执行之间变化很大,则对一组理想的参数进行一次编译可能会为该查询生成出色的查询计划,但对其他人来说则很差。 )。我的猜测是,您可能不会像处理糟糕的计划重用所带来的影响那样糟糕。
你能为这个做什么?
Optimize For Ad Hoc Workloads当然可以帮助解决内存问题,因为在第一次执行时只将计划的存根存储在缓存中,并且直到使用相同计划第二次执行时才会存储完整计划。
强制参数化在这里也有帮助。它有时会强制进行参数化,并有助于解决缓存膨胀问题和重新编译的成本。
修复查询理想情况下,您不应该求助于这些选项,而是可以在您的数据库开发中更加严格,鼓励计划重用,考虑存储过程的所有好处,并尝试通过这种方式解决问题。通过强制参数化或针对临时优化来帮助解决此问题的方法很有帮助,但最佳解决方案始终针对根本原因。
这里有一个很好的资源,它讨论了计划缓存污染的一些危险以及您可以做的一些事情。我建议在这里阅读。它是为 SQL Server 2012 编写的,但概念和解决方案适用。
归档时间: |
|
查看次数: |
4212 次 |
最近记录: |