_ Table "public.events"
Column | Type | Modifiers
------------------+-----------------------------+--------------------------------------------------------
id | integer | not null default nextval('events_id_seq'::regclass)
duration | integer | not null
start_at | timestamp without time zone |
Indexes:
"events_pkey" PRIMARY KEY, btree (id)
"my_idx" Gist (tsrange(start_at, end_at(events.*), '[)'::text))
_
_CREATE FUNCTION end_at(rec events)
RETURNS timestamp without time zone
IMMUTABLE
LANGUAGE SQL
AS $$
SELECT $1.start_at + ($1.duration * ('00:00:01'::interval));
$$;
_
インデックスは次のようなクエリに使用されます。
_-- check if current time is within the start and end times
-- of event
where localtimestamp <@ tsrange(start_at, events.end_at, '[)')
_
そしてそれはうまくいきます。
現在の時刻が終了した後のイベントを照会したい。これを行う方法について私が知っている方法:
where tsrange(localtimestamp, localtimestamp, '[]') >> tsrange(start_at, events.end_at, '[)')
。これが私が望むセマンティクスであると私はかなり確信しています、そして_explain analyze
_はそれがインデックスを使用していると言います、しかしそれは少し醜いです、そしてこれを表現するより良い方法があるかどうか疑問に思っています(そしてそれが漠然と不確かです私は範囲に慣れていないので、必要なセマンティクス)。where localtimestamp > upper(tsrange(start_at, events.end_at, '[)'))
+ upper(tsrange(start_at, events.end_at, '[)'))
のbtreeインデックス。これはうまく機能しますが、別のインデックスを維持する必要があります。where localtimestamp > events.end_at
_。 + _events.end_at
_のbtreeインデックス。上記と同じ状況。上記の最初の箇条書きを達成するためのよりエレガントな(または正しい)方法はありますか?
これに取り組む方法についての他のアイデアはありますか?
Postgresはこのための演算子をサポートしていません。 @ evan-carrollによって指摘されたように、おそらく可能であり、そうすべきです。
したがって、最良の解決策は
where tsrange(localtimestamp, localtimestamp, '[]') >> tsrange(start_at, events.end_at, '[)')
現在の時刻が終了した後のイベントを照会したい。これを行う方法について私が知っている方法:
ここに要旨演算子 が表示されます。リストはrange_ops
で確認できます。
&& &> &< >> << <@ -|- = @> @>
あなたがおそらく望むものは<<
、>>
です。 <<
を使用します。
醜いですか?はい。範囲タイプは、両側で範囲を操作する場合に最適ですが、ここではそうではありません。テーブルに範囲タイプを格納することすらありません。そうすることをお勧めします。
このインデックス条件が機能するかどうかはわかりませんが、
"my_idx" Gist (tsrange(start_at, end_at(events.*), '[)'::text))
あなたはそれをテストしましたか?つまり、PostgreSQLはstart_at
が機能することを確認できますが、私の想定では、end_at
をevents.*
で使用するのは十分スマートではありません(end_at
で使用されている値(列)の1つがテーブル作成から呼び出されるように変更された場合はどうなりますか? 、どうやってPostgreSQLはそれを知るのでしょうか)。私はtsrange
をテーブルに格納し、関連するすべての列を削除します。
以下を無視して調べます。
また、rhs範囲を構築しないことで、短くすることを検討できます。
SELECT tsrange('yesterday', 'tomorrow') @> timestamp without time zone 'now'; SELECT tsrange('yesterday', 'tomorrow') @> 'now'::timestamp without time zone;
または、その形式を好む場合など。または、アンチパターンのように見える次のようになります。
SELECT tsrange('yesterday', 'tomorrow') @> '[now,now]';
または、tstzrange
を使用することもできます(これは、おそらく全体的に優れたアイデアです)。
SELECT tstzrange('yesterday', 'tomorrow') @> now();