web-dev-qa-db-ja.com

Postgresでタイムスタンプを5分に切り捨てる最も速い方法は何ですか?

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以降と互換性がある)があるのか​​疑問に思っています。

48
DNS

より速い方法はないと思います。

そして、表現のパフォーマンスについて心配する必要はないと思います。

(SELECT、UPDATE、...)ステートメントの実行に関係する他のすべてのものは、おそらく日付/時刻の計算よりもはるかにコストがかかります(たとえば、行を取得するためのI/O)。

14

私も同じことを考えていました。私はこれを行う2つの代替方法を見つけましたが、あなたが提案した方法はより高速でした。

私は、より大きなテーブルの1つに対して非公式にベンチマークを行いました。クエリを最初の400万行に制限しました。私は2つのクエリを交互に使用して、dbキャッシングによる不当な利点を1つ与えないようにしました。


エポック/ 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秒
  • 実行: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秒

システム

  • DBバージョン:gcc(Ubuntu 4.8.2-19ubuntu1)4.8.2、64ビットでコンパイルされたx86_64-pc-linux-gnu上のPostgreSQL 9.6.2
  • コア:Intel®Xeon®、E5-1650v2、Hexa-Core
  • RAM:64 GB、DDR3 ECC RAM

結論

あなたのバージョンはより速いようです。しかし、私の特定のユースケースには十分な速度ではありません。時間を指定する必要がないという利点により、Epochバージョンがより用途が広くなり、クライアント側のコードでより簡単なパラメーター化が行われます。 2 hour間隔だけでなく5 minuteバンプする必要のない間隔date_trunc時間単位の引数がアップしています。最後に、この時間単位の引数を時間間隔の引数に変更したいと思います。

12

疑問に思っている人のための完全なクエリ(@DNSの質問に基づく):

注文があり、5minのスライスと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