web-dev-qa-db-fra.com

Quel est le moyen le plus rapide de tronquer les horodatages à 5 minutes dans Postgres?

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é.

48
DNS

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.

14

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.


Passer par Epoch/Unix Time

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

  • Exécuter 1: 39,368 secondes
  • Exécuter: 39,526 secondes
  • Exécuter 5: 39,883 secondes

Utilisation de date_trunc et 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

Résultats

  • Exécuter 2: 34,189 secondes
  • Exécuter 4: 37,028 secondes
  • Exécuter 6: 32,397 secondes

Système

  • Version DB: PostgreSQL 9.6.2 sur x86_64-pc-linux-gnu, compilé par gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2, 64 bits
  • Cœurs: Intel® Xeon®, E5-1650v2, Hexa-Core
  • RAM: 64 Go, RAM DDR3 ECC

Conclusion

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.

12
André C. Andersen

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
1