Postgres peut arrondir (tronquer) les horodatages en utilisant la fonction date_trunc, comme ceci:
date_trunc('hour', val)
date_trunc('minute', val)
Je cherche un moyen de tronquer un horodatage à la limite de 5 minutes la plus proche afin que, par exemple, 14:26:57 devienne 14:25:00. La façon la plus simple de le faire est la suivante:
date_trunc('hour', val) + date_part('minute', val)::int / 5 * interval '5 min'
Comme il s'agit d'une partie de la requête critique pour les performances, je me demande s'il s'agit de la solution la plus rapide ou s'il existe un raccourci (compatible avec Postgres 8.1+) que j'ai négligé.
Je ne pense pas qu'il y ait de méthode plus rapide.
Et je ne pense pas que vous devriez vous inquiéter de la performance de l'expression.
Tout ce qui est impliqué dans l'exécution de votre instruction (SELECT, UPDATE, ...) est probablement beaucoup plus cher (par exemple les E/S pour récupérer des lignes) que ce calcul de date/heure.
Je me demandais la même chose. J'ai trouvé deux façons de procéder, mais celle que vous avez suggérée était plus rapide.
J'ai comparé de manière informelle à l'une de nos plus grandes tables. J'ai limité la requête aux 4 premiers millions de lignes. J'ai alterné entre les deux requêtes afin d'éviter de donner un avantage injuste en raison de la mise en cache de la base de données.
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
(Notez que cela produit timestamptz
même si vous avez utilisé un type de données ignorant le fuseau horaire)
Résultats
SELECT
date_trunc('hour', ht.time)
+ date_part('minute', ht.time)::int / 5 * interval '5 min'
FROM huge_table AS ht LIMIT 4000000
Résultats
Système
Votre version semble être plus rapide. Mais pas assez rapide pour mon cas d'utilisation spécifique. L'avantage de ne pas avoir à spécifier l'heure rend la version Epoch plus polyvalente et simplifie le paramétrage dans le code côté client. Il gère 2 hour
intervalles aussi bien que 5 minute
intervalles sans avoir à heurter les date_trunc
argument d'unité de temps vers le haut. Pour terminer, j'aimerais que cet argument d'unité de temps soit remplacé par un argument d'intervalle de temps.
Requête complète pour ceux qui se demandent (basée sur la question @DNS):
En supposant que vous ayez des commandes et que vous souhaitiez les compter par tranches de 5min et 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