Как лучше написать этот запрос LINQ

У меня есть один запрос Linq. Когда я запускаю запрос, только для 10 записей его занимает 13 секунд, чтобы извлечь данные в модель. Мне нужно знать, что запрос, который я написал, хорош для производительности или нет. Пожалуйста, расскажите мне, что я делаю неправильно.

код

var stocktakelist = (from a in Db.Stocktakes
 select new ExportStock
 {
 Id = a.Id,
 ItemNo = a.ItemNo,
 AdminId = (from admin in Db.AdminAccounts where admin.Id == a.Id select admin.Name).FirstOrDefault(),
 CreatedOn = a.CreatedOn,
 Status = (from items in Db.Items where items.ItemNo == a.ItemNo select items.ItemStatu.Description).FirstOrDefault(),
 Title = (from tit in Db.BibContents where tit.BibId == (from bibs in Db.Items where bibs.ItemNo == a.ItemNo select bibs.BibId).FirstOrDefault() && tit.TagNo == "245" && tit.Sfld == "a" select tit.Value).FirstOrDefault() // This line of Query only makes the performance Issue
 }
 ).ToList();

Спасибо

4 ответа

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

from a in Db.Stocktakes
join admin in Db.AdminAccounts
 on a.Id equals admin.Id
into adminJoinData
from adminJoinRecord in adminJoinData.DefaultIfEmpty( )
join items in Db.Items
 on a.ItemNo equals items.ItemNo
into itemsJoinData
from itemsJoinRecord in itemsJoinData.DefaultIfEmpty( )
join title in Db.BibContents
 (
 from subQuery in Db.BibContents
 where subQuery.TagNo == "245"
 where subQuery.Sfld == "a"
 select subquery
 )
 on title.BibId equals itemsJoinRecord.BidId
into titleJoinData
from titleJoinRecord in titleJoinData.DefaultIfEmpty( )
select new ExportStock( )
{
 Id = a.Id,
 ItemNo = a.ItemNo,
 AdminId = adminJoinRecord.Name,
 CreatedOn = a.CreatedOn,
 Status = itemsJoinRecord.ImemStatu.Description,
 Title = titleJoinRecord.Value
}


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

Чтобы узнать, как присоединиться, в Интернете есть много ресурсов в зависимости от типа используемого LINQ.

Если вы извлекаете эти данные с SQL-сервера, возможно, стоит заняться этой интенсивной работой в SQL - это то, для чего был разработан SQL, и это намного быстрее, чем .NET. EDIT: Как показано ниже, работа выполняется в SQL, если используется LINQ to SQL/Entities и используется правильный синтаксис соединения.


Как говорили другие, вы должны использовать Left Outer Joins в своем LINQ так же, как если бы вы записывали его в SQL.

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

var a = from a in Db.Stocktakes
 join admin in Db.AdminAccounts on admin.Id equals a.Id into tmpAdmin
 from ad in tmpAdmin.DefaultIfEmpty()
 join item in Db.Items on item.ItemNo equals a.ItemNo into tmpItem
 from it in tmpItem.DefaultIfEmpty()
 join title in Db.BibContents on bib.BibId equals items.BibId into tmpTitle
 from ti in tmpTitle.DefaultIfEmpty()
 where ti.TagNo == "245" 
 && ti.Sfld == "a"
 select new ExportStock
 {
 Id = a.Id,
 ItemNo = a.ItemNo,
 AdminId = ad == null ? default(int?) : ad.Id,
 CreatedOn = a.CreatedOn,
 Status = it == null ? default(string) : it.ItemStatus.Description,
 Title = ti == null ? default(string) : ti.Value
 };


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

Db.Stocktakes
 .Join(Db.AdminAccounts, a => a.Id, b => b.Id, (a,b) => new { a, AdminId = b.Name })
 .Join(Db.Items, a => a.ItemNo, b => b.ItemNo, (a,b) => new { a, Status = b.ItemStatus.Description, BidId = b.BibId })
 .Join(Db.BibContents, a => a.BibId, b => b.BibId, (a,b) => new { a, Value = b.Value, TagNo = b.TagNo, Sfld = b.Sfld })
 .Where(a => a.TagNo == "245" && a.Sfld == "a")
 .Select(a => 
 new ExportStock { Id = a.Id, 
 ItemNo = a.ItemNo,
 AdminId = a.AdminId,
 CreatedOn = a.CreatedOn,
 Status = a.Status,
 Title = a.Value
 }
 ).ToList();

licensed under cc by-sa 3.0 with attribution.