Вы говорите о некоторых довольно сложных проблемах, которые, к сожалению, Rails полностью игнорирует.Документы ActiveRecord :: Calculations написаны так, как будто они все, что вам когда-либо нужно, но базы данных могут делать гораздо более сложные вещи.Как отметил Донал Феллоуз в своем комментарии, проблема гораздо сложнее, чем кажется.
За последние два года я разработал приложение Rails, которое интенсивно использует агрегацию, и я пробовал несколько разныхподходы к проблеме.К сожалению, я не могу позволить себе игнорировать такие вещи, как летнее время, потому что статистика - это «только тренды».Мои расчеты проверяются моими клиентами на предмет точных спецификаций.
Чтобы немного расширить проблему, я думаю, вы найдете, что ваше текущее решение по группировке по датам неадекватно.Это кажется естественным вариантом использования STRFTIME.Основная проблема заключается в том, что она не позволяет группировать по произвольным периодам времени.Если вы хотите выполнить агрегацию по году, месяцу, дню, часу и / или минуте, STRFTIME будет работать нормально.Если нет, вы найдете другое решение.Другая огромная проблема - проблема агрегации при агрегации.Скажем, например, вы хотите группировать по месяцам, но вы хотите делать это с 15 числа каждого месяца.Как бы вы сделали это с помощью STRFTIME?Вы должны были бы группировать по каждому дню, а затем по месяцу, но тогда кто-то учитывает начальное смещение 15-го числа каждого месяца.Последняя капля заключается в том, что для группировки по STRFTIME требуется группировка по строковому значению, которое вы найдете очень медленным при выполнении агрегации при агрегации.
Наиболее производительное и наилучшее решение, к которому я пришел, - это решение на основецелые периоды времени.Вот выдержка из одного из моих запросов mysql:
SELECT
field1, field2, field3,
CEIL((UNIX_TIMESTAMP(CONVERT_TZ(date, '+0:00', @@session.time_zone)) + :begin_offset) / :time_interval) AS time_period
FROM
some_table
GROUP BY
time_period
В этом случае: time_interval - это количество секунд в периоде группировки (например, 86400 для ежедневного), а: begin_offset - это количество секунд досмещение периода начала.Бизнес CONVERT_TZ () учитывает то, как mysql интерпретирует даты.Mysql всегда предполагает, что поле даты находится в местном часовом поясе mysql.Но поскольку я храню время в UTC, я должен преобразовать его из UTC в часовой пояс сеанса, если я хочу, чтобы функция UNIX_TIMESTAMP () давала мне правильный ответ.Период времени заканчивается целым числом, которое описывает количество интервалов времени с начала времени Unix.Это решение гораздо более гибкое, поскольку позволяет группировать по произвольным периодам и не требует агрегирования при агрегировании.
Теперь, чтобы перейти к моей реальной точке.Для надежного решения я бы порекомендовал вам вообще не использовать Rails для генерации этих запросов.Самая большая проблема заключается в том, что характеристики производительности и тонкости агрегирования в разных базах данных различны.Вы можете найти один дизайн, который хорошо работает в вашей среде разработки, но не в производстве или наоборот.Вы перепрыгнете через много обручей, чтобы Rails хорошо работал с обеими базами данных при построении запросов.
Вместо этого я бы порекомендовал вам генерировать специфичные для базы данных представления в выбранной вами базе данных и переносить их вправильная среда.Попробуйте смоделировать представление так же, как любую другую таблицу ActiveRecord (идентификаторы и все), и, конечно, сделайте поля в представлении идентичными для всех баз данных.Поскольку эти статистические данные предназначены только для чтения, вы можете использовать модель для их поддержки и притворяться, будто они являются полноценными таблицами.Просто вызовите исключение, если кто-то попытается сохранить, создать, обновить или уничтожить.
Мало того, что вы получите упрощенное управление моделью, выполняя действия Rails, вы также обнаружите, что вы можете писать модульные тесты дляваши функции агрегирования такими способами, о которых вы не мечтали бы в чистом SQL.И если вы решите переключить базы данных, вам придется переписать эти представления, но ваши тесты покажут вам, где вы не правы, и сделают жизнь намного проще.