Эффективно ли написан этот запрос LINQ с усреднением и группировкой по часам? - PullRequest
2 голосов
/ 18 февраля 2010

Это мой первый реальный запрос LINQ-to-SQL. Мне было интересно, если я делаю какие-либо большие, очевидные ошибки.

У меня есть таблица среднего размера (2M + записи, добавление 13 тыс. В день) с данными, dataTypeID, machineID и dateStamp. Я хотел бы получить среднее, минимальное и максимальное значения данных со всех компьютеров и определенного типа данных в течение 4 часов, в течение 28 дней.

* 1005 например *

DateTime Avg Мин. Макс.
1/1/10 12:00 AM 74,2 72,1 75,7
1/1/10 04:00 AM 74,5 73,1 76,2
1/1/10 08:00 утра 73,7 71,5 74,2
1/1/10 12:00 PM 73,2 71,2 76,1
и т. д.
1/28/10 00:00 AM 73,1 71,3 75,5

До сих пор мне удавалось группировать средние значения только с шагом в 1 час, но я мог бы, вероятно, справиться с этим, если альтернативы слишком беспорядочные.

Код:

var q =
    from d in DataPointTable
    where d.dateStamp > DateTime.Now.AddDays(-28) && (d.dataTypeID == (int)dataType + 1)
    group d by new {
        d.dateStamp.Year,
        d.dateStamp.Month,
        d.dateStamp.Day,
        d.dateStamp.Hour
    } into groupedData
    orderby groupedData.Key.Year, groupedData.Key.Month, groupedData.Key.Day, groupedData.Key.Hour ascending
    select new {
        date = Convert.ToDateTime(
            groupedData.Key.Year.ToString() + "-" +
            groupedData.Key.Month.ToString() + "-" +
            groupedData.Key.Day.ToString() + " " + 
            groupedData.Key.Hour.ToString() + ":00"
            ),
        avg = groupedData.Average(d => d.data),
        max = groupedData.Max(d => d.data),
        min = groupedData.Min(d => d.data)
    };

1 Ответ

3 голосов
/ 18 февраля 2010

Если вы хотите увеличение на 4 часа, разделите час на 4 (используя целочисленное деление), а затем умножьте на 4 при создании нового элемента datetime. Обратите внимание, что вы можете просто использовать конструктор, который берет год, месяц, день, час, минуту и ​​секунду вместо того, чтобы создавать строку и конвертировать ее.

var q = 
    from d in DataPointTable 
    where d.dateStamp > DateTime.Now.AddDays(-28) && (d.dataTypeID == (int)dataType + 1) 
    group d by new { 
        d.dateStamp.Year, 
        d.dateStamp.Month, 
        d.dateStamp.Day, 
        Hour = d.dateStamp.Hour / 4
    } into groupedData 
    orderby groupedData.Key.Year, groupedData.Key.Month, groupedData.Key.Day, groupedData.Key.Hour ascending 
    select new { 
        date = new DateTime(
            groupedData.Key.Year, 
            groupedData.Key.Month, 
            groupedData.Key.Day, 
            (groupedData.Key.Hour * 4),
            0, 0), 
        avg = groupedData.Average(d => d.data), 
        max = groupedData.Max(d => d.data), 
        min = groupedData.Min(d => d.data) 
    };

Для повышения эффективности вы можете рассмотреть возможность добавления индекса в столбец dateStamp. Учитывая, что вы выбираете только небольшой диапазон дат, использование индекса должно стать значительным преимуществом. Я ожидаю, что план запроса выполнит поиск по индексу для первой даты, что сделает его еще быстрее.

...