EF Core 3, оптимизация множества Include / ThenInclude - PullRequest
4 голосов
/ 09 мая 2020

У меня есть такой запрос

return await _ctx.Activities
            .Include(a => a.Attributes)
            .Include(a => a.Roles)
            .Include(a => a.Bookmarks)
            .Include(a => a.VideoMetas)
                .ThenInclude(vm => vm.Instances)
            .Include(a => a.ImageMetas)
                .ThenInclude(im => im.Instances)
            .Include(a => a.Procedure)
                .ThenInclude(p => p.Attributes)
            .FirstOrDefaultAsync(a => a.Id == id);

, который оказывается очень медленным. В EF 6 вы можете сделать .Include(v => v.VideoMetas.Select(vm => vm.Instances), что немного быстрее (я думаю, не смотрел SQL Profiler и фактический запрос tbh). Как я могу это оптимизировать? Я также могу использовать EF Plus там, где есть .IncludeOptimized(), но для .ThenInclude() нет версии. Я слышал, что могу использовать .Select вместо .Include(), но действительно не уверен, как я могу справиться с этим в этом запросе.

Ответы [ 4 ]

4 голосов
/ 10 мая 2020

Вы захотите разделить его на несколько запросов, чтобы повысить производительность. Для этого можно использовать явную загрузку. Это не самое красивое решение, но оно работает. Надеюсь, в EF 5 появится более простое решение.

Я немного догадываюсь, какие поля являются коллекциями, а какие - «обычными» записями, но примерно так:

var activity = await _ctx.Activities.FindAsync(Id);

await context.Entry(activity)
    .Collection(a => a.Attributes)
    .LoadAsync();

await context.Entry(activity)
    .Collection(a => a.Roles)
    .LoadAsync();

await context.Entry(activity)
    .Collection(a => a.Bookmarks)
    .LoadAsync();

await context.Entry(activity)
    .Collection(a => a.VideoMetas)
    .Query()
    .Include(vm => vm.Instances)
    .LoadAsync();

await context.Entry(activity)
    .Collection(a => a.ImageMetas)
    .Query()
    .Include(im => im.Instances)
    .LoadAsync();

await context.Entry(activity)
    .Reference(a => a.Procedure)
    .Query()
    .Include(p => p.Attributes)
    .LoadAsync();

return activity;
2 голосов
/ 09 мая 2020

Нельзя. Это пространственное расширение SQL сражается с. В Ef 2.2 было то, что можно было рассматривать как попытку начать с этого, но они не заставили его работать и удалили его.

Ваш лучший шанс - загрузить несколько (возможно, параллельных) запросов, а затем сшить результаты вместе в памяти. Для EF есть библиотеки для этого - не уверен, что они существуют для EfCore. Они выполняют запросы как несколько запросов.

0 голосов
/ 09 мая 2020

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

0 голосов
/ 09 мая 2020

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

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