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
を変換します 値eventtime
timestamptz
へ 現在のタイムゾーンのタイムオフセットを追加します。タイムゾーンを使用する場合名前 (数値のオフセットや省略形ではありません)。これは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でタイムゾーンを完全に無視する