LINQ Multiple GroupBy Query执行速度比T-SQL慢几倍

时间:2014-07-21 17:41:34

标签: c# sql performance linq group-by

我对LINQ完全不熟悉。

我有一个SQL GroupBy,只需几毫秒就可以运行。但是当我试图通过LINQ实现同样的事情时,它似乎非常缓慢。 我想要实现的是获取ceratin数据库更新的平均每月持续时间。

在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信息的表中获取记录,然后对相关信息进行过滤和分组。

    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语句?

1 个答案:

答案 0 :(得分: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。您需要提供您的上下文/模型信息