EF Core Lazy загружается очень медленно - PullRequest
0 голосов
/ 03 ноября 2018

Я сделал небольшой тест, включающий Ленивый loading.optionsBuilder.UseLazyLoadingProxies().UseSqlServer(ConnectionString);

(с EF Core 2.1.4)

Я перебираю инструменты с и без, и вот результаты, которые я получаю

Дело 1

var instruments = db.instruments.OrderBy(t=>t.id).Include(t=>t.NavPro1).ThenInclude(t=>t.NavPro2).Take(200);

Дело 2

var instruments = db.instruments.OrderBy(t=>t.id).Include(t=>t.NavPro1).ThenInclude(t=>t.NavPro2).Take(200);

Тогда

   foreach (var i in instruments)
   {
        var props = i.NavPro1;
        foreach (var prop in props)
        {
            sbPrintGreeks.AppendLine(prop.NavPro2.Name + " - " + prop.id + " - " + prop.Value);
        }
   }

Занимает 7 с, чтобы получить 100 000 строк без ленивой загрузки

Требуется 160 с, чтобы получить 3 тыс. Строк с отложенной загрузкой.

Что можно сделать, чтобы получить достойную производительность?

Ответы [ 3 ]

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

Да, избегайте ленивой загрузки. Период.

Проблема в том, что, возвращаясь к каждой когда-либо созданной ORM, проблема заключается в том, что если вы выполняете отложенную загрузку, то каждая ссылка является отложенной загрузкой. Это 1+ поездки туда и обратно (по одному на собственность, минимум). Отдельное выполнение SQL, отдельное сетевое время. Это складывается очень быстро.

Именно поэтому каждый написанный ORM поддерживает не ленивую загрузку в варианте EF с помощью операторов .Include, которые либо расширяют SQL, либо генерируют отдельный SQL (например, core, tolist для материализации отношений с эффективным sql).

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

Теперь, добавляя к этому, любое ядро ​​EF до версии 3.0 сломано настолько, насколько это возможно. И да, это 3.0 - даже не 2.2. Видите, есть множество проблем с различными частями, в том числе довольно простой LINQ. И производительность. По крайней мере, 2,2 (ожидается через месяц) должно решить некоторые проблемы. А пока попробуйте использовать .Include и AsNoTracking - потому что в IIRC есть ошибка производительности, которая также может поразить вас при загрузке 200 тыс. Строк.

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

https://github.com/aspnet/EntityFrameworkCore/issues/12451

Это решение

Услуги .AddDbContext (b => b.ReplaceService ());

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

Это общая проблема, известная как проблема N + 1.

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

В случае, когда вы используете Include, у вас есть один огромный запрос, который дает вам все данные - или, возможно, один запрос на таблицу, так что три запроса в вашем случае. Это зависит от точной структуры ваших данных.

В случае с отложенной загрузкой у вас есть один запрос для инструментов, и для каждого инструмента у вас есть другой запрос для NavPro1. И для каждого элемента NavPro1 у вас есть еще один запрос для NavPro2.

Итак, если у вас есть 1000 инструментов, и у каждого есть 10 NavPro1, теперь у вас есть 1 + (1000 * (1 + 10)) = 11001 запросов вместо максимум трех запросов. Это медленно, точка.

...