EF4 - Eager加载速度低于延迟加载?

时间:2011-08-02 17:44:24

标签: entity-framework-4 lazy-loading

我有一个由几个实体组成的数据模型,所有实体都是相互关联的,总共大约有80个表。

我开始以生产形式获取代码,并且在这个过程中我将从延迟加载所有内容(它使我的开发生活更容易)转换为在我不需要所有相关数据的情况下进行急切加载,或者它只是表示要发送给客户端的数据太多,这只是浪费带宽。

然而,我只是注意到,对于至少一些实体来说,急切加载我需要的东西比延迟加载所有数据要慢得多。

这是一个例子,我可以懒惰加载“请求”对象:

db.ContextOptions.LazyLoadingEnabled = true;
request = db.requests.Where(rq => rq.idrequest == rID).FirstOrDefault();

或急切地说:

db.ContextOptions.LazyLoadingEnabled = false;
request = db.request_objects.Include("service_objects.task_objects.task_parameters.parameter_values.address1").Include("service_objects.task_objects.task_parameters.parameter_values.attachment").
                            Include("service_objects.task_objects.task_parameters.parameter_values.phone_nbrs").Include("service_objects.task_objects.task_parameters.parameter_values.stored_texts").
                            Include("service_objects.task_objects.parent_tasks").Include("service_objects.task_objects.contact_objects").
                            Include("service_objects.service_parameters.parameter_values.address1").Include("service_objects.service_parameters.parameter_values.attachment").
                            Include("service_objects.service_parameters.parameter_values.phone_nbrs").Include("service_objects.service_parameters.parameter_values.stored_texts").
                            Include("service_objects.stored_texts").
                            Include("request_attachments.attachment").Include("request_notes.note").
                            Include("request_contacts.contact_objects").Include("contact_objects").
                            Include("contact_objects1").Include("contact_objects2").
                            Include("request_objects_links.request_objects1").Include("stored_texts").
                            Include("company_objects").
                            Where(ro => ro.idrequest_objects == rID).FirstOrDefault();

在大多数情况下,急切加载请求比懒惰加载要快几百倍或几千倍(!!!),尽管延迟加载通常会加载大量额外数据。 我的意思是,使用急切加载需要2到3秒,而在大多数情况下(通常小于10毫秒)延迟加载需要不到40毫秒(我使用System.diagnostics.Stopwatch获得了这些时间)。

我不是SQL专家,对SQL优化一无所知,但我无法完全理解为什么加载更少的数据更加昂贵。

我的任何见解或明显的错误? 谢谢!

修改

从Brokenglass的回答来看,我不够清楚:o)。这段代码只是WCF服务函数的一部分,非常简单:

[OperationContract]
public request LoadRequestByID(int rID)
{
  request res = null;
  try
  {
    DBEntities db = new DBEntities();
    res = db.request_objects.Where(ro => ro.idrequest_objects == rID).FirstOrDefault();
  }
  catch (Exception e)
  {
    //Error log
  }
  return res;
}

当我注意到在eager-loading而不是延迟加载时,在客户端显示请求的详细信息(在调用上面的函数之后)花了相当长的时间,我决定计时。

2 个答案:

答案 0 :(得分:3)

这很有趣。实际上,加载加载较少的数据并不是真的。它会加载更多,因为您的所有包含都会合并到single enormous data set中。延迟加载的问题是每个延迟加载的属性导致额外的数据库查询=往返数据库。在您的本地计算机上可以超快,但是一旦您的数据库服务器位于网络的其他位置,它就会非常慢。

所以主要建议是:

  • 测量真实生产环境中的性能。
  • 确保整个图表确实加载了延迟加载。您可以忘记将单个导航属性标记为虚拟,并且根本不会加载一半数据。 (如果您从T4模板中自动生成实体,则不应该这样做。)
  • 确保您在客户端上传输您真正需要的数据。转移所有数据只是为了让一切变得简单并不总是双赢的解决方案。

答案 1 :(得分:1)

您目前正在将苹果与橙子进行比较:

db.ContextOptions.LazyLoadingEnabled = true;
request = db.requests.Where(rq => rq.idrequest == rID).FirstOrDefault();

这只是启用延迟加载,但加载本身尚未完成 - 在显式访问这些属性之前,尚未加载所有相关实体。

你说明的第二种情况会导致相应数据库表的连接,这自然比从一个表中取一行慢得多 - 但它会检索你需要的所有数据。