EF4 - Быстрая загрузка медленнее, чем отложенная загрузка? - PullRequest
1 голос
/ 02 августа 2011

У меня есть модель данных, состоящая из нескольких сущностей, все они связаны между собой, всего около 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 секунд, в то время как в большинстве случаев это занимает менее 40 мс (часто менее 10 мс) при отложенной загрузке (я получал это время с помощью System.diagnostics.Stopwatch).

Я не эксперт по SQL, и я ничего не знаю об оптимизации SQL, но я не могу понять, почему загрузка меньшего количества данных стоит дороже.

Любое понимание илиочевидная ошибка с моей стороны?Спасибо!

РЕДАКТИРОВАТЬ

Судя по ответу Брокенгласс, я не достаточно ясно: о).Этот код является лишь частью сервисной функции 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;
}

Я решил рассчитать время, когда заметил, что отображение деталей запроса на стороне клиента заняло значительно больше времени (после вызова вышеупомянутогофункция) при активной загрузке, а не при отложенной загрузке.

Ответы [ 2 ]

3 голосов
/ 03 августа 2011

Ну, это интересно. Это на самом деле не правда, что стремительная загрузка загружает меньше данных Он загружает гораздо больше, потому что все ваши включения объединяются в огромный набор данных . Проблема отложенной загрузки состоит в том, что каждое отложенное загруженное свойство приводит к дополнительному запросу к базе данных = возврат к базе данных. Это может быть очень быстрым на вашем локальном компьютере, но может быть чертовски медленным, если ваш сервер базы данных будет где-то еще в вашей сети.

Итак, основные советы:

  • Измерение производительности в реальной среде производства
  • Убедитесь, что весь ваш график действительно загружен отложенной загрузкой. Вы можете где-нибудь забыть пометить одно свойство навигации как виртуальное, и половина ваших данных не будет загружена вообще. (Это не должно происходить, если у вас есть автоматически сгенерированные объекты из шаблона T4).
  • Убедитесь, что вы передаете данные, которые вам действительно нужны, на клиенте. Передача всех данных просто для упрощения - не всегда беспроигрышное решение.
1 голос
/ 02 августа 2011

Вы сравниваете яблоки с апельсинами в настоящее время:

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

Это просто включает отложенную загрузку , но сама загрузка еще не была выполнена - все связанные объекты не были загружены док этим свойствам обращаются явно.

Второй иллюстрируемый вами случай приведет к объединению соответствующих таблиц БД, что, естественно, намного медленнее, чем просто извлечение одной строки из одной таблицы, но при этом будут получены все данные, которыевам нужно заранее.

...