Любой способ улучшить этот запрос EF - PullRequest
0 голосов
/ 29 ноября 2018

В WebApi, который используют третьи стороны, сегодня мы начали испытывать сбои при вызове метода.

Метод подключается к паре таблиц и соединяет их.Сообщение об ошибке от EF:

Процессору запросов не хватило внутренних ресурсов, и он не смог создать план запроса.Это редкое событие и ожидается только для чрезвычайно сложных запросов или запросов, которые ссылаются на очень большое количество таблиц или разделов.Пожалуйста, упростите запрос.Если вы считаете, что получили это сообщение по ошибке, обратитесь в Службу поддержки клиентов для получения дополнительной информации.

return context.leads
            .Where(q => q.eventID == 1234)
            .Join(context.config,
                leads => leads.configId,
                config => config.configId,
                (leads, config) => new { leads, config })
            .Where(p => keys.Contains(p.leads.leadId))

ключи - это IEnumerable из полученных идентификаторов.По сути, мы извлекаем список идентификаторов, а затем делаем вышеуказанное, проверяя набор ключей, чтобы наш запрос возвращал точные данные.

ключи содержат около 28 тыс. Идентификаторов.

Обратите внимание, что это только началосьпроблема с момента перехода в облако Azure, но я думаю, что это совпадение

Ответы [ 2 ]

0 голосов
/ 30 ноября 2018

Чтобы уточнить ответ Дэвида:

Какой запрос вы использовали для получения идентификаторов 28k?Это запрос, который вы должны объединить с этим запросом.Выборка идентификаторов работает хорошо для сравнительно небольших # идентификаторов, а не 28 КБ.Если вы правильно настроите отношения в EF, вы можете избежать явных объединений.EF - это не просто оболочка для замены SQL.Несмотря на то, что вы можете написать его с явными объединениями между отключенными объектами, он намного более эффективен, если настроен как ORM, где связанные объекты знают друг о друге.Ваше выражение EF должно выглядеть примерно так:

var leadsQuery = context.leads
    .Include(l => l.Config)  
    .Where(l => l.eventID == 1234
      && /* Insert criteria to determine which Leads to return. /*);

Положения where для вставки - это , а не из IEnumerable из идентификаторов.Это прекрасно работает для небольшого количества строк.Вместо этого это должны быть критерии, которые вы использовали для получения этих идентификаторов.

Свинец должен иметь ссылку на Конфиг.Не нужно объявлять DbSets для каждой таблицы, а затем указывать EF присоединиться к ним.Если ведущая таблица имеет ConfigId, то:

public class Lead
{
   //...
   public virtual Config Config { get; set; }
}

, тогда, если это ядро ​​EF, настройте отображение: (IEntityTypeConfiguration или OnModelCreating)

builder.Entity<Lead>()
  .HasOne(x => x.Config)
  .WithMany() // Lead has a config, Config does not have a collection of Leads.
  .HasForeignKey("ConfigId"); // Creates a shadow property for the FK.

или EF 6

builder.Entity<Lead>()
  .HasRequired(x => x.Config)
  .WithMany()
  .Map(x => x.MapKey("ConfigId")); // Similar to above. Set up the relationship without a FK in the entity, map directly to the table.

Используя .Include(l => l.Config), вы можете получить доступ к свойству lead.Config, чтобы получить Config для этого отведения.Нет необходимости писать запросы, чтобы возвращать лиды, конфиги и другие данные отдельно.Вам не нужно .Include() связанных сущностей для запроса к ним, однако, если вы хотите получить доступ к этим сущностям после запроса через свойства, вы должны использовать .Include(), чтобы избежать дополнительных отложенных вызовов обратно в базу данных.(Мощная функция EF, но дорогая, если не использовать ее осторожно.)

0 голосов
/ 29 ноября 2018

keys - это IEnumerable из полученных идентификаторов.

keys содержит около 28k идентификаторов.

Итак, вставим:

return context.leads
            .Where(q => q.eventID == 1234)
            .Join(context.config,
                leads => leads.configId,
                config => config.configId,
                (leads, config) => new { leads, config })
            .Where(p => keys.Contains(p.leads.leadId))

идентификаторы в тексте SQL-запроса, например:

SELECT … WHERE LeadId in (1,23,3,4,5,6,45,34, . . . )

, что приводит к большому, не подлежащему повторному использованию и дорогостоящему анализу и компиляции запроса.Лучше загрузить идентификаторы в таблицу и присоединить их, либо передать их на сервер с помощью XML, JSON или табличного параметра.

По сути, мы извлекаем список идентификаторов, а затем делаемвыше

Тогда не делай этого.Если требуемый список идентификаторов находится в базе данных, включите его в свой запрос.Старайтесь не считывать идентификаторы 28 КБ из базы данных, а затем отправлять их обратно в тело запроса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...