LINQ Multiple GroupBy Query Выполнение в несколько раз медленнее, чем T-SQL

1

Я абсолютно не знаком с 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();

Я знаю, что GroupBy в LINQ не совпадает с GroupBy в T-SQL, но не уверен, что происходит за кулисами. Может ли кто-нибудь объяснить разницу и что происходит в памяти, когда я запускаю версию LINQ? После того, как я сделал.ToList() после того, как первые вещи GroupBy стали немного быстрее. Но даже тогда этот способ поиска средней продолжительности очень медленный. Какая была бы лучшая альтернатива и есть способы улучшить медленную инструкцию LINQ с помощью Visual Studio 2012?

  • 2
    Вы должны проверить, как выглядит сгенерированный SQL.
  • 0
    спасибо @MarcinJuraszek. Я проверил это, и это было совсем не то, что я ожидал. Благодаря LINQPad.
Теги:
linq
performance
group-by

1 ответ

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

Если у вас все еще есть проблемы, нам нужно будет знать, используете ли вы сущность или linq-to-sql. И вам нужно будет предоставить информацию о вашем контексте/модели

  • 0
    ваш linq даст мне среднюю продолжительность в день. Я хотел это в месяц. вот почему у меня была дополнительная группа. Я только учусь Linq. поэтому не знаю, какие термины вы упомянули => linq-> entity / linq-> objects. погуглив это сейчас. Я попробую немного изменить свой подход и опробую его. спасибо за совет. Я дам вам знать, как проходит мой тест.
  • 0
    Немного поняла про Linq to Entities. Я проверил SQL оператора LINQ, который я написал с помощью LinqPad, и кажется, что для него создано несколько 100 SQL-операторов. Поэтому я думаю, что я должен явно объединить сущности, используя то выражение, которое вы дали. проверяя это сейчас.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню