我有DbContext(称为“MyContext”),里面有大约100个DbSets。
在域类中,我有一个包含10个直接子类的Document类(如PurchaseOrder,RequestForQuotation等)。 层次结构用TPT策略映射。 也就是说,在我的数据库中,有一个Document表,其他表如PurchaseOrder,RequestForQuotation用于子类。
当我进行如下查询时:
Document document = myContext.Documents.First();
查询耗时5秒,无论是我第一次运行还是随后运行。
如下的查询:
Document document = myContext.Documents.Where(o => o.ID == 2);
也花了很长时间。
这是EF4.1的问题(如果是这样,EF4.2会有帮助)还是这是查询代码的问题?
答案 0 :(得分:3)
我不确定代码优先暴露的DbSet实际上是否使用了ObjectQuery,但您可以尝试在它们上调用.ToTraceString()方法来查看生成的SQL,如下所示:
var query = myContext.Documents.Where(o => o.ID == 2);
Debug.WriteLine(query.ToTraceString());
获得SQL后,您可以确定是导致延迟的查询还是EF。根据基类的复杂性,查询可能包含许多其他列,可以使用投影来避免。使用投影,您可以执行以下查询:
var query = from d in myContext.Documents
where d.ID == 2
select new
{
o.Id
};
这基本上应该执行SELECT ID FROM Documents WHERE ID = 2
查询,您可以衡量获取更多信息所需的时间。当然,预计的查询可能不符合您的需求,但它可能会让您走上正确的轨道。如果这仍然需要5秒钟,您应该查看数据库本身的性能问题,而不是EF。
<强>更新强> 显然,使用代码优先,您可以使用.ToString()而不是.ToTraceString(),感谢Slauma注意到。
答案 1 :(得分:3)
您是否尝试使用SQL配置文件查看实际发送到数据库的内容?可能是您的Document上有太多连接未设置为延迟加载,因此查询必须一次完成所有连接,从而返回太多列。尝试仅使用一个返回列发送简单查询。
答案 2 :(得分:3)
正如您可以阅读here,有关EF中TPT的一些性能问题。
EF小组在June 2011 CTP中发布了多项修正,包括TPT查询优化,但它们未包含在EF 4.2中,因为您可以在this answer的评论中阅读。
在最坏的情况下,这些修补程序只会在.NET 4.5中发布。我希望它能早点......
答案 3 :(得分:1)
我刚刚在一个存储过程中在ExecuteFunction上有5秒的延迟,该存储过程在从SQL Management Studio调用时立即运行。我通过重写程序来修复它。
似乎EF(和SSRS BTW)尝试对存储过程进行“准备”以及可能需要很长时间的一些(通常是复杂的)过程。
快速而肮脏的解决方案是复制,然后用内部变量替换SP参数:
create proc ListOrders(@CountryID int = 3, @MaxOrderCount int = 20)
as
declare @CountryID1 int, @MaxOrderCount1 int
set @CountryID1 = @CountryID
set @MaxOrderCount1 = @MaxOrderCount
select top (@MaxOrderCount1) *
from Orders
where CountryID = @CountryID1