SQL Group по годам, месяцам, неделям, дням, часам SQL по сравнению с процедурной производительностью - PullRequest
22 голосов
/ 27 января 2009

Мне нужно написать запрос, который сгруппирует большое количество записей по периодам времени от года до часа.

Мой первоначальный подход состоял в том, чтобы процедурно определять периоды в C #, проходить через каждый из них и запускать SQL, чтобы получить данные за этот период, создавая набор данных по ходу работы.

SELECT Sum(someValues)
FROM table1
WHERE deliveryDate BETWEEN @fromDate AND @ toDate

Впоследствии я обнаружил, что могу сгруппировать записи, используя Year (), Month () Day () и datepart (неделя, дата) и datepart (чч, дата).

SELECT Sum(someValues)
FROM table1
GROUP BY Year(deliveryDate), Month(deliveryDate), Day(deliveryDate)

Меня беспокоит то, что использование datepart в группе по приведет к ухудшению производительности, чем многократный запуск запроса в течение заданного периода времени из-за невозможности эффективного использования индекса в поле datetime; какие-либо мысли о том, правда ли это?

Спасибо.

Ответы [ 7 ]

9 голосов
/ 27 января 2009

Как и все, что связано с производительностью Мера

Проверка плана запроса для второго подхода заранее сообщит вам о любых очевидных проблемах (полное сканирование таблицы, когда вы знаете, что она не нужна), но ничто не заменит измерения. В тестировании производительности SQL это измерение должно выполняться с соответствующими размерами тестовых данных.

Поскольку это сложный случай, вы не просто сравниваете два разных способа выполнения одного запроса, но сравниваете подход с одним запросом и итеративный, аспекты вашей среды могут играть важную роль в фактической производительности.

В частности

  1. «расстояние» между вашим приложением и базой данных, поскольку задержка каждого вызова будет напрасной тратой времени по сравнению с подходом с одним большим запросом
  2. Используете ли вы подготовленные операторы или нет (что приводит к дополнительным усилиям синтаксического анализа для механизма базы данных при каждом запросе)
  3. дорого ли само построение диапазонов (сильно зависит от 2)
6 голосов
/ 27 января 2009

Если вы поместите формулу в полевую часть сравнения, вы получите сканирование таблицы .

Индекс на поле, а не на части даты (поле), , поэтому ВСЕ поля должны быть вычислены - так что я думаю, что ваша догадка верна.

5 голосов
/ 27 января 2009

Если вы можете терпеть снижение производительности при объединении еще одной таблицы, у меня есть предложение, которое кажется странным, но работает очень хорошо.

Создайте таблицу, которую я назову ALMANAC со столбцами, такими как день недели, месяц, год. Вы даже можете добавить столбцы для специфических для компании особенностей даты, например, является ли дата выходным днем ​​компании или нет. Возможно, вы захотите добавить начальную и конечную метки времени, как указано ниже.

Хотя вы могли бы обходиться с одним рядом в день, когда я делал это, мне было удобно ходить с одним рядом в смену, где в день три смены. Даже при такой скорости период в десять лет составлял чуть более 10000 строк.

Когда вы пишете SQL для заполнения этой таблицы, вы можете использовать все ориентированные на дату встроенные функции, чтобы упростить работу. Когда вы собираетесь выполнять запросы, вы можете использовать столбец даты в качестве условия соединения или вам могут потребоваться две временные метки, чтобы обеспечить диапазон для захвата временных меток в пределах диапазона. В остальном это так же просто, как работать с любыми другими видами данных.

5 голосов
/ 27 января 2009

вы могли бы сделать что-то похожее на это:

SELECT Sum(someValues)
FROM 
(
    SELECT *, Year(deliveryDate) as Y, Month(deliveryDate) as M, Day(deliveryDate) as D
    FROM table1
    WHERE deliveryDate BETWEEN @fromDate AND @ toDate
) t
GROUP BY Y, M, D
2 голосов
/ 16 марта 2009

Я искал подобное решение для целей отчетности и наткнулся на статью под названием Группировать по месяцам (и другим периодам времени) . Он показывает различные способы, хорошие и плохие, для группировки по полю datetime. Определенно стоит посмотреть.

1 голос
/ 27 января 2009

Возможно, вы захотите взглянуть на многомерный подход (это похоже на то, что предложил Уолтер Митти), где каждая строка имеет внешний ключ для измерения даты и / или времени. Это дает возможность очень гибкого суммирования через соединение с этой таблицей, где эти части предварительно рассчитаны. В этих случаях ключ, как правило, представляет собой натуральный целочисленный ключ в форме YYYYMMDD и HHMMSS, который является относительно быстродействующим и также читаемым человеком.

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

Или вычисленные столбцы.

Но производительность должна быть проверена и планы выполнения проверены ...

1 голос
/ 27 января 2009

Я думаю, что вы должны сравнить его, чтобы получить надежные результаты, но, IMHO, и моей первой мыслью будет то, что позволить БД позаботиться об этом (ваш второй подход) будет намного быстрее, чем когда вы делаете это в коде своего клиента , При первом подходе у вас есть несколько обращений к БД, которые, я думаю, будут намного дороже. :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...