2014-07-21 69 views
1

我完全不熟悉LINQ。我有一个SQL GroupBy,它几乎运行几毫秒。但是当我尝试通过LINQ实现同样的事情时,它似乎非常缓慢。 我试图实现的是获取平均每月持续时间的角蛋白数据库更新。LINQ Multiple GroupBy Query比T-SQL慢几倍

在SQL =>

select SUBSTRING(yyyyMMdd, 0,7), 
     AVG (duration) 
    from (select (CONVERT(CHAR(8), mmud.logDateTime, 112)) as yyyyMMdd, 
       DateDIFF(ms, min(mmud.logDateTime), max(mmud.logDateTime)) as duration 
      from mydb.mydbo.updateData mmud 
      left 
      join mydb.mydbo.updateDataKeyValue mmudkv 
      on mmud.updateDataid = mmudkv.updateDataId 
      left 
      join mydb.mydbo.updateDataDetailKey mmuddk 
      on mmudkv.updateDataDetailKeyid = mmuddk.Id 
     where dbname = 'MY_NEW_DB' 
      and mmudkv.value in ('start', 'finish')    
     group 
      by (CONVERT(CHAR(8), mmud.logDateTime, 112)) 
     ) as resultSet 
    group 
    by substring(yyyyMMdd, 0,7) 
    order 
    by substring(yyyyMMdd, 0,7) 

在LINQ =>我第一次提取的表中的链接数据库名称和的UpdateData的信息的记录,然后做过滤和GROUPBY上的相关信息。

entry.updatedata.Where(
     ue => ue.updatedataKeyValue.Any(
        uedkv => 
        uedkv.Value.ToLower() == "starting update" || 
        uedkv.Value.ToLower() == "client release")) 
     .Select(
      ue => 
      new 
       { 
        logDateTimeyyyyMMdd = ue.logDateTime.Date, 
        logDateTime = ue.logDateTime 
       }) 
     .GroupBy(
      updateDataDetail => updateDataDetail.logDateTimeyyyyMMdd) 
     .Select(
      groupedupdatedata => new 
       { 
        UpdateDateyyyyMM = groupedupdatedata.Key.ToString("yyyyMMdd"), 
        Duration = 
             (groupedupdatedata.Max(groupMember => groupMember.logDateTime) - 
             groupedupdatedata.Min(groupMember => groupMember.logDateTime) 
             ) 
             .TotalMilliseconds 
       } 
     ). 
      ToList(); 
var updatedataMonthlyDurations = 
    updatedataInDateRangeWithDescriptions.GroupBy(ue => ue.UpdateDateyyyyMM.Substring(0,6)) 
              .Select(
               group => 
               new updatedataMonthlyAverageDuration 
                { 
                 DbName = entry.DbName, 
                 UpdateDateyyyyMM = group.Key.Substring(0,6), 
                 Duration = 
                  group.Average(
                   gmember => 
                   (gmember.Duration)) 
                } 
     ).ToList(); 

我知道LINQ中的GroupBy和T-SQL中的GroupBy不一样,但不知道幕后会发生什么。任何人都可以解释这种差异,当我运行LINQ版本时会发生什么?在第一个GroupBy之后,我做了.ToList()之后,事情变得更快了。但即使如此,找到平均持续时间的方式确实很慢。 什么是最好的选择,并且有没有使用Visual Studio 2012改进慢速LINQ语句的方法?

+2

您应该检查生成的SQL的外观。 – MarcinJuraszek

+0

谢谢@MarcinJuraszek。我检查了它,这完全不是我所期望的。感谢LINQPad。 –

回答

1

您的linq查询大部分工作都在linq-to-objects之内。您应该构建一个linq-to-entities/sql查询,一次性生成完整查询。

您的查询似乎有一个冗余的group by子句,但我不确定哪个表dbname来自哪个表,但以下查询应该能帮助您找到正确的方向。

var query = from mmud in context.updateData 
      from mmudkv in context.updateDataKeyValue 
            .Where(x => mmud.updateDataid == x.updateDataId) 
            .DefaultIfEmpty() 
      from mmuddk in context.updateDataDetailKey 
            .Where(x => mmudkv.updateDataDetailKeyid == x.Id) 
            .DefaultIfEmpty() 
      where mmud.dbname == "MY_NEW_DB" 
      where mmudkv.value == "start" || mmudkv.value == "finish" 
      group mmud by mmud.logDateTime.Date into g 
      select new 
      { 
       Date = g.Key, 
       Average = EntityFunctions.DiffMilliseconds(g.Max(x => x.logDateTime), g.Min(x => x.logDateTime)), 
      }; 

var queryByMonth = from x in query 
        group x by new { x.Date.Year, x.Date.Month } into x 
        select new 
        { 
        Year = x.Key.Year, 
        Month = x.Key.Month, 
        Average = x.Average(y => y.Average) 
        }; 

// Single sql statement is to sent to your database 
var result = queryByMonth.ToList(); 

如果您仍然有问题,我们需要知道您是否正在使用entityframework或linq-to-sql。并且您将需要提供您的上下文/型号信息

+0

你的linq会给我每天的持续时间。我每月都想要它。这就是为什么我有额外的groupby。我只学习linq。所以不知道你提到的术语=> linq-> entities/linq->对象。现在使用Google搜索。我会尝试改变我的方法并测试一下。感谢提示。我会让你知道我的考试是如何进行的。 –

+0

了解了一些关于Linq to Entities的内容。我检查了我使用LinqPad编写的LINQ语句的SQL,并且似乎在后台创建了几百条SQL语句。所以我想我必须使用你提供的表达方式显式地加入实体。现在测试。 –

+0

@EakanGopalakrishnan - 我按月修改了平均答案。 – Aducci