2009-11-23 116 views
1

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

这是我们正在使用的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,因为它相当大。如果有人有想法,请随时提供意见。

谢谢。

+0

你说得对。它看起来很疯狂。实际上,您需要每个实体的每个字段,包括*和*您打算更新每个实例*和*您已经分析并发现这比单个需求加载更快?这是我可以想到的唯一合理的论点,而不是投影(我的第一选择只读用例)或闯入较小的查询。 – 2009-11-23 20:01:54

回答

1

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

服务器有多少内存?

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

我建议你用内置的性能计数器进行监测:SQL Server, Plan Cache Counters。从过程缓存

执行计划

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

当用户进程插入一个 执行计划到高速缓存中, 用户进程设置当前成本 等于原始查询编译 成本;对于临时执行计划, 用户进程将当前成本设置为 零。此后,每当用户 处理引用执行计划 时,它将当前成本重置为原始编译成本;对于特设的 执行计划,用户进程 增加当前成本。对于所有 计划, 当前成本的最大值是原始编译 成本。

内存时的压力存在, 数据库引擎通过从程序 缓存 执行计划响应。要确定删除哪些计划,数据库引擎会重复检查每个执行的状态 计划,并在其当前成本为零时删除计划。一个执行 计划与零当前成本不是 当内存 压力存在时自动删除;当数据库引擎检查 计划并且当前成本为零时,它仅被删除 。 检查执行计划时,如果当前正在使用该计划的查询不是 ,则 数据库引擎会通过减少 当前成本将当前的 成本推向零。

数据库引擎反复 检查执行计划,直到 足够已被删除,以满足 内存要求。虽然内存压力存在,但执行计划可能会增加成本,并且可能会多次减少 。当内存压力 不再存在,数据库引擎 停止下降的 未使用执行计划的当前成本和所有 执行计划留在 过程缓存,即使他们的成本 为零。

数据库引擎使用资源 监视器和用户线程释放 内存从过程缓存 响应内存压力。 资源监视器和用户线程可以同时运行 检查计划到 减少每个 未使用的执行计划的当前成本。当存在全局内存 压力时,资源 监视器将从 中删除执行计划。它将内存释放到 为系统内存强制执行策略, 进程内存,资源池内存, 和所有高速缓存的最大大小。

所有缓存的最大大小为 函数的缓冲池大小,并且 不能超过最大服务器内存的 。有关配置最大服务器内存的 的详细信息,请参阅 sp_configure(Transact-SQL)中的最大服务器内存设置 。

如果您尚未看到它:Plan Caching in SQL Server 2008

+0

该服务器有8 GB的RAM,但没有处于高负载状态。但是如果有办法确认它会很好。 – Lukasz 2009-11-23 14:55:53

1

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

例如

SELECT * FROM MyTable WHERE [email protected] 

优于

SELECT * FROM MyTable WHERE ID=1 

为同样的计划将被缓存和重用,不管是什么@Id的值。执行计划被重用的越多,它就越有可能停留在缓存中,因为它被认为是有用的。

我不知道LINQ创建的语句的类型,但值得注意。正如Mitch所说,你拥有的内存越多,你可以在缓存中存储的内存就越多。

另外,请注意,这不仅仅是在这里工作的执行计划缓存。您还拥有数据缓存,它在性能上有着巨大的差异 - 一旦执行了一次查询,数据就会保存在数据缓存中,以便后续调用时数据已经存储在内存中 - 这是大部分性能差异。

+0

LINQ to Entities生成参数化的sql,所以我不认为这是问题。感谢您的文章! – Lukasz 2009-11-23 15:03:30

+0

啊好的。请注意我最近对数据缓存的最新编辑 - 这对性能来说是一个巨大的挑战 – AdaTheDev 2009-11-23 15:04:33