timestampに対する回答
データ型の性質を理解する必要がありますtimestamp (timestamp without time zone )およびtimestamptz (timestamp with time zone )。そうでない場合は、最初にこれを読んでください:
- RailsとPostgreSQLでタイムゾーンを完全に無視する
AT TIME ZONE コンストラクトはtimestampを変換します timestamptzへ 、これはほぼ間違いなく間違った動き あなたの場合:
where eventtime at time zone 'CET' between '2015-06-16 06:00:00'
and '2015-06-17 06:00:00'
最初 、パフォーマンスを低下させます。 AT TIME ZONEを適用する 列eventtime 式を引数不可にします 。 Postgresはeventtimeでプレーンインデックスを使用できません 。ただし、インデックスがなくても、引数可能な式の方が安価です。すべての行の値を操作するのではなく、フィルター値を調整します。
できます 一致する式インデックスで補正しますが、それはおそらく単なる誤解であり、とにかく間違っています。
その表現で何が起こりますか?
-
AT TIME ZONE 'CET'timestampを変換します 値eventtimetimestamptzへ 現在のタイムゾーンのタイムオフセットを追加します。タイムゾーンを使用する場合名前 (数値のオフセットや省略形ではありません)。これはDSTルール(夏時間)も考慮に入れるため、「冬」のタイムスタンプに対して異なるオフセットを取得します。基本的に、あなたは質問に対する答えを得る:指定されたタイムゾーンの指定されたタイムスタンプに対応するUTCタイムスタンプは何ですか?
表示時 ユーザーへの結果は、セッションの現在のタイムゾーンに対応するタイムオフセットを持つローカルタイムスタンプとしてフォーマットされます。 (式で使用されているものと同じである場合とそうでない場合があります。)
-
右側の文字列リテラルにはデータ型がないため、型は式の割り当てから派生します。それは
timestamptzなので 現在、両方がtimestamptzにキャストされています 、セッションの現在のタイムゾーンを想定しています。現在のセッションのタイムゾーン設定の特定のタイムスタンプに対応するUTCタイムスタンプは何ですか。
オフセットはDSTルールによって異なる場合があります。
短編小説 、常に 同じタイムゾーンで動作する:CET または'Europe/Berlin' -現在のタイムスタンプについても同じですが、過去のタイムスタンプや(おそらく)将来のタイムスタンプについてはそうではありません。
2番目の問題 次の式を使用します: ほとんどの場合、BETWEEN timestampは間違っています 値。参照:
- 日付ステートメント間の最適化
- PostgreSQLで重複する日付範囲を見つける
SELECT date_trunc('hour', eventtime) AS hour
, count(DISTINCT serialnumber) AS ct -- sure you need distinct?
FROM t_el_eventlog
WHERE eventtime >= now()::date - interval '18 hours'
AND eventtime < now()::date + interval '6 hours'
AND sourceid = 44 -- don't quote the numeric literal
GROUP BY 1
ORDER BY 1;
now() SQL標準のPostgres実装ですCURRENT_TIMESTAMP 。どちらもtimestamptzを返します (timestampではありません !)。どちらでも使用できます。now()::date CURRENT_DATEと同等です 。どちらも現在のタイムゾーン設定によって異なります。
インデックスが必要です フォームの:
CREATE INDEX foo ON t_el_eventlog(sourceid, eventtime)
または、インデックスのみのスキャンを許可するには:
CREATE INDEX foo2 ON t_el_eventlog(sourceid, eventtime, serialnumber)
異なるタイムゾーンで操作する場合は、事態がさらに複雑になるため、timestamptzを使用する必要があります。 すべてのために。
timestamptzの代替
質問が更新される前は、タイムゾーンが重要であるように見えました。さまざまなタイムゾーンを扱う場合は、「今日」 現在のタイムゾーンの機能依存性です。人々はそれを忘れがちです。
セッションの現在のタイムゾーン設定を操作するには、上記と同じクエリを使用します。別のタイムゾーンで実行すると、実際には結果が間違っています。 (上記にも当てはまります。)
セッションの現在のタイムゾーン設定に関係なく、特定のタイムゾーン(この場合は「ヨーロッパ/ベルリン」)で正しい結果を保証するには、代わりに次の式を使用します。
((now() AT TIME ZONE 'Europe/Berlin')::date - interval '18 hours')
AT TIME ZONE 'Europe/Berlin' -- 2nd time to convert back
AT TIME ZONEに注意してください コンストラクトはtimestampを返します timestamptzの場合 入力およびその逆。
冒頭で述べたように、ここにあるすべての厄介な詳細:
- RailsとPostgreSQLでタイムゾーンを完全に無視する