Поиск записей в базе данных по списку идентификаторов - PullRequest
0 голосов
/ 05 февраля 2019

У меня есть список идентификаторов (itemID), которые я передаю в запрос следующим образом:

 using (var ctx = new MyEntities())
            {
                ctx.Configuration.LazyLoadingEnabled = false;
                ctx.Configuration.AutoDetectChangesEnabled = false;
                ctx.Configuration.ValidateOnSaveEnabled = false;
                ctx.Configuration.ProxyCreationEnabled = false;
                var storeItems = ctx.Items.AsNoTracking().Where(y => y.StoreID == 223250).ToList();
                var idList = storeItems.Select(y => y.Id).ToList();
                var storeTransactions = ctx.ItemTransactions.AsNoTracking().Where(r => idList.Contains(r.Id.Value)).ToList();
                return Json("Ok");
            }

Чтобы быстро подвести итог ... список StoreItems, например, элемент 1001 в этом случае ...

И, передав идентификатор элемента 1001 для извлечения транзакций элемента, я получаю результат

265000 записей ...

Две таблицы не связаны между собойотношение, но столбец Id индексируется для улучшения результата ...

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

Кто-нибудь знает, есть ли еще что-то, чего мне не хватает, чтобы ускорить выполнение этого последнего запроса при получении транзакций для элементов??

Может ли кто-нибудь мне помочь?

Ответы [ 3 ]

0 голосов
/ 05 февраля 2019

Нет необходимости отключать опцию LazyLoadingEnabled в базе данных и использовать AsQueryable, чтобы ids не было в памяти.Я бы рекомендовал использовать join в этом случае.

Попробуйте это:

using ( var ctx = new MyEntities() )
{
    ctx.Configuration.LazyLoadingEnabled = true;
    ctx.Configuration.AutoDetectChangesEnabled = false;
    ctx.Configuration.ValidateOnSaveEnabled = false;
    ctx.Configuration.ProxyCreationEnabled = false;

    var idList = ctx.Items.AsNoTracking().Where( y => y.StoreID == 223250 ).Select( y => y.Id ).AsQueryable();

    var storeTransactions = ctx.ItemTransactions.AsNoTracking().Where( r => idList.Contains( r.Id.Value ) ).ToList();

    return Json( "Ok" );
}
0 голосов
/ 06 февраля 2019

Вы писали:

Две таблицы не связаны каким-либо отношением

Ну, очевидно, есть какое-то отношение.Вы ожидаете, что ItemTranaction.Id.Value иногда имеет значение Item.Id

. Вы получаете все Предметы с StoreId, равным 223250. Получите Идентификатор от этих предметов.Дайте мне все ItemTransaction, которые имеют значение Id.Value, которое также есть в извлеченных идентификаторах.

Другими словами:

Требование : Дайте мне все ItemTransactions,со значением itemTransaction.Id.Value, равным одному из идентификаторов всех элементов с StoreId, равным 223250

Ваш запрос будет выполняться намного быстрее, если вы выполните его в одном запросе:

int storeId = 223250;

var result = dbContext.ItemTransactions
  .Join(dbContext.Items.Where(item => item.StoreId == storeId),
  itemTransaction => itemTransaction.Id.Value,
  item => item.Id,
  (itemtransaction, item) => itemTransaction)

Другими словами:

  • Присоединитесь к транзакции item с элементами, у которых StoreId равен storId.
  • Из каждой itemTransaction берется itemTransaction.Id.Value,
  • Из каждого элемента возьмите Id
  • , когда эти значения равны, возьмите itemTransaction и элемент для создания результата
  • этот результат является itemTransaction

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

0 голосов
/ 05 февраля 2019

Проблема в том, что вы получаете список доступных идентификаторов в память, а затем используете его для повторного запроса.Это означает, что EF переведет его как простой IN запрос со всеми жестко закодированными идентификаторами.На самом деле я даже подозреваю, что, поскольку число 265000 записей слишком велико, сначала он действительно получает все ItemTransactions из БД, а затем выполняет запрос в памяти.Это вызывает плохую производительность.Но простое изменение значительно улучшит производительность:

using (var ctx = new MyEntities())
{
    ctx.Configuration.LazyLoadingEnabled = false;
    ctx.Configuration.AutoDetectChangesEnabled = false;
    ctx.Configuration.ValidateOnSaveEnabled = false;
    ctx.Configuration.ProxyCreationEnabled = false;
    var storeItems = ctx.Items.AsNoTracking().Where(y => y.StoreID == 223250);
    var idList = storeItems.Select(y => y.Id); //removed ToList on this and previous line
    var storeTransactions = ctx.ItemTransactions.AsNoTracking()
                               .Where(r => idList.Contains(r.Id.Value)).ToList();
    return Json("Ok");
}

Единственное изменение, которое я сделал, - это удаление ToList() вызовов в вашем коде.Это будет означать, что idList - это IQueryable<int>, который EF может понять, и вместо того, чтобы выполнять его первым, он будет использовать его как подзапрос или JOIN в последнем утверждении - что будет иметь значительно лучшую производительность.

Также подумайте, действительно ли вам нужны экземпляры ItemTransactions в целом или вы можете использовать проекцию с Select для запроса только тех свойств, которые вам действительно нужны.Это уменьшит объем данных, которые должны передаваться между вашим приложением и базой данных.

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