SQL Server查询执行计划重建

时间:2009-11-23 14:41:06

标签: tsql sql-server-2008 linq-to-entities

我有这个查询,通过Linq to Entities执行。第一次运行查询时,它会生成执行计划,该计划只需不到2分钟。计划缓存后,查询需要1或2秒。我遇到的问题是计划每隔几个小时就会重建一次,我不确定为什么会这样?

这是我们正在使用的linq查询,我知道它看起来很疯狂,但是对于我们需要的东西,这是我们唯一的选择。

var data = from row in mgr.ServiceDesk_RequestEvent
    .Include("ServiceDesk_Event")
    .Include("ServiceDesk_Event.ServiceDesk_SLAEventRule")
    .Include("ServiceDesk_Event.ServiceDesk_SLAEventRule.ServiceDesk_RuleSet")
    .Include("ServiceDesk_Event.ServiceDesk_SLAEventRule.ServiceDesk_RuleSet.ServiceDesk_Rule")
    .Include("ServiceDesk_Event.ServiceDesk_SLAEventRule.ServiceDesk_RuleSet.ServiceDesk_Rule.ServiceDesk_RuleOperator")
    .Include("ServiceDesk_Event.ServiceDesk_SLAEventRule.ServiceDesk_RuleSet.ServiceDesk_Rule.ServiceDesk_RuleConstraintField")
    .Include("ServiceDesk_Event.ServiceDesk_SLAEventRule.ServiceDesk_RuleSet.ServiceDesk_Rule.ServiceDesk_RuleConstraintValue")
    .Include("ServiceDesk_Event.ServiceDesk_SLAEventRule.ServiceDesk_RuleSet.ServiceDesk_Action")
    .Include("ServiceDesk_Request")
    .Include("ServiceDesk_Request.People_User")
    .Include("ServiceDesk_Request.ServiceDesk_RequestCategory")
    .Include("ServiceDesk_Request.ServiceDesk_RequestCategory.ServiceDesk_SLA")
    .Include("ServiceDesk_Request.ServiceDesk_RequestRole_Groups")
    .Include("ServiceDesk_Request.ServiceDesk_RequestRole_Groups.Security_Role.Security_UserRoles")
    .Include("ServiceDesk_Request.ServiceDesk_RequestRole_Groups.Security_Role.Security_UserRoles.Security_User")
    .Include("ServiceDesk_Request.ServiceDesk_RequestPriority")
    .Include("ServiceDesk_Request.Offices_User")
    .Include("ServiceDesk_Request.ServiceDesk_RequestTechnicians")
    .Include("ServiceDesk_Request.ServiceDesk_RequestTechnicians.People")
    where row.Completed == false && row.Deleted == false
    select row;

我不想在这里粘贴生成的t-sql,因为它非常大。如果有人有想法,请随时贡献。

谢谢。

2 个答案:

答案 0 :(得分:1)

可能的原因是您的服务器处于内存压力之下,这会导致查询计划缓存更快地回收。

服务器有多少RAM?

重新阅读你的问题,这一行有点担心:“第一次查询运行时会产生执行计划,只需不到2分钟”。第一次进行简单查询需要2分钟很长时间。您是否在SQL Server框上运行任何其他应用程序(希望不是)?

我建议您使用内置性能计数器进行监控:SQL Server, Plan Cache Counters

  

从过程缓存中删除执行计划

     

执行计划保留在过程缓存中   因为有足够的内存来存储   他们。当存在压力时,   数据库引擎使用基于成本的   确定执行的方法   计划从程序中删除   缓存。要做出基于成本的决策,   数据库引擎增加了   减少当前的成本变量   每个执行计划根据   以下因素。

     

当用户进程插入时   执行计划进入缓存,   用户进程设置当前成本   等于原始查询编译   成本;对于临时执行计划,   用户进程将当前成本设置为   零。此后,每次都是用户   流程引用执行计划,   它重置当前的成本   原始编译成本;特别的   执行计划用户进程   增加当前成本。对全部   计划,最大值   当前成本是原始编译   成本。

     

当存在内存压力时,   数据库引擎通过删除进行响应   程序执行计划   缓存。确定哪些计划   重复删除数据库引擎   检查每次执行的状态   计划并删除他们的计划   目前的成本为零。执行   没有当前成本的计划   内存时自动删除   压力存在;它只被删除   当数据库引擎检查时   计划和当前成本为零。   在检查执行计划时,   数据库引擎推送当前   通过降低成本来降低成本   如果查询不是,则为当前成本   目前正在使用该计划。

     

重复数据库引擎   检查执行计划,直到   足够的已被删除以满足   内存要求。而记忆   压力存在,执行计划可能   它的成本增加和减少   不止一次。当记忆压力   不再存在,数据库引擎   停止降低当前的成本   未使用的执行计划和所有   执行计划仍然存在   程序缓存,即使它们的成本是   零。

     

数据库引擎使用该资源   监视器和用户线程免费   来自过程缓存的内存   对记忆压力的反应。该   资源监视器和用户线程可以   检查计划同时运行   降低每个人的当前成本   未使用的执行计划资源   monitor从中删除执行计划   全局内存时的过程缓存   压力存在。它释放内存   强制执行系统内存策略,   进程内存,资源池内存,   和所有缓存的最大大小。

     

所有缓存的最大大小为a   缓冲池大小和函数的函数   不能超过最大服务器   记忆。有关的更多信息   配置最大服务器内存,   请参阅中的最大服务器内存设置   sp_configure(Transact-SQL)。

如果您还没有看到它:Plan Caching in SQL Server 2008

答案 1 :(得分:1)

This MSDN article是执行计划缓存的一个很好的参考。优化执行计划使用的一种方法是使用参数化SQL而不是硬编码/动态SQL。

e.g。

SELECT * FROM MyTable WHERE ID=@Id

优于

SELECT * FROM MyTable WHERE ID=1

因为无论@Id的值是什么,都可以缓存和重用相同的计划。重用执行计划越多,就越有可能在缓存中保留,因为它被认为是有用的。

我不知道LINQ创建的语句类型,但值得记住。同样如Mitch所说,你拥有的内存越多,你在缓存中存储的内存就越多。

另外,请注意,这不仅仅是执行计划缓存。你也有数据缓存,它在性能上有很大差异 - 一旦你执行了一次查询,数据将被保存在数据缓存中,以便后续调用数据已经存储在内存中 - 这是大多数数据源的来源。性能差异。