如何以更好的方式编写此LINQ查询

时间:2013-01-04 13:06:40

标签: asp.net-mvc-3 linq c#-4.0

我有一个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 个答案:

答案 0 :(得分:2)

之所以这么慢是因为它在外部LINQ语句中为每个项运行3个内部LINQ语句。 使用LINQ连接只会运行4个查询,然后将它们链接在一起,这样会更快。

要了解如何加入,互联网上有大量资源,具体取决于您使用的LINQ类型。

如果你是从SQL服务器检索这些数据,也许可以考虑在SQL中进行这项密集工作 - 这就是SQL的设计目标,它比.NET快得多。 编辑:如下所示,如果使用LINQ to SQL / Entities并使用正确的连接语法,则 在SQL中完成。

答案 1 :(得分:1)

正如其他人所说,你应该在你的LINQ中使用Left Outer Joins,就像在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
    };

答案 2 :(得分:1)

我试图用一些连接来创建相应的查询来练习。 我无法测试它,我不是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 :(得分:0)

使用lambda表达式,您的查询将如下所示:

        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();