Какой самый быстрый способ урезать метки времени до 5 минут в Postgres? - PullRequest
36 голосов
/ 04 сентября 2011

Postgres может округлять (усекать) временные метки с помощью функции date_trunc, например:

date_trunc('hour', val)
date_trunc('minute', val)

Я ищу способ урезать временную метку до ближайшей 5-минутной границы, например,14:26:57 становится 14:25:00.Простой способ сделать это выглядит следующим образом:

date_trunc('hour', val) + date_part('minute', val)::int / 5 * interval '5 min'

Так как это критичная для производительности часть запроса, я задаюсь вопросом, является ли это самым быстрым решением или есть какой-либо ярлык (совместимый сPostgres 8.1+), который я пропустил.

Ответы [ 3 ]

14 голосов
/ 04 сентября 2011

Я не думаю, что есть более быстрый метод.

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

Все остальное, что задействовано в выполнении вашего оператора (SELECT, UPDATE, ...), скорее всего, намного дороже (например, ввод / вывод для извлечения строк), чем вычисление даты / времени.

10 голосов
/ 26 марта 2017

Мне было интересно то же самое.Я нашел два альтернативных способа сделать это, но тот, который вы предложили, был быстрее.

Я неофициально провел сравнение с одним из наших больших столов.Я ограничил запрос первыми 4 миллионами строк.Я чередовал два запроса, чтобы избежать несправедливого преимущества одного из них из-за кеширования БД.


Пройдя время эпохи / unix

SELECT to_timestamp(
    (EXTRACT(epoch FROM ht.time) / EXTRACT(epoch FROM interval '5 min'))::int 
    * EXTRACT(epoch FROM interval '5 min')
) FROM huge_table AS ht LIMIT 4000000

(обратите внимание, что это приводит к timestamptz даже если вы использовали тип данных, не связанный с часовым поясом)

Результаты

  • Прогон 1 : 39,368 секунд
  • Прогон 3 : 39,526 секунд
  • Прогон 5 : 39,883 секунд

Использование date_trunc и date_part

SELECT 
    date_trunc('hour', ht.time) 
    + date_part('minute', ht.time)::int / 5 * interval '5 min'
FROM huge_table AS ht LIMIT 4000000

Результаты

  • Прогон 2 : 34,189 секунд
  • Прогон 4 : 37,028 секунд
  • Запуск 6 : 32,397 секунд

Система

  • Версия БД: PostgreSQL 9.6.2 включенx86_64-pc-linux-gnu, скомпилированный gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2, 64-битный
  • Ядра: Intel® Xeon®, E5-1650v2, Hexa-Core
  • RAM: 64 ГБ, DDR3 ECC RAM

Заключение

Ваша версия, кажется, быстреер.Но не достаточно быстро для моего конкретного случая использования.Преимущество отсутствия указания часа делает версию эпохи более универсальной и упрощает параметризацию в коде на стороне клиента.Он обрабатывает интервалы 2 hour так же, как интервалы 5 minute, без необходимости увеличения аргумента date_trunc единицы времени.В заключение я хотел бы, чтобы вместо этого аргумента единицы времени был изменен аргумент временного интервала.

1 голос
/ 06 апреля 2016

Полный запрос для тех, кто интересуется (на основе вопроса @DNS):

При условии, что у вас есть заказы, и вы хотите посчитать их по кусочкам по 5 минут и shop_id:

SELECT date_trunc('hour', created_at) + date_part('minute', created_at)::int / 5 * interval '5 min' AS minute
      , shop_id, count(id) as orders_count
FROM orders
GROUP BY 1, shop_id
ORDER BY 1 ASC
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...