web-dev-qa-db-ja.com

tsrangeのGistインデックスを使用して、範囲の後に時間が発生するかどうかを確認する最良の方法は何ですか?

テーブル(簡略化)

_                                        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インデックス。上記と同じ状況。

上記の最初の箇条書きを達成するためのよりエレガントな(または正しい)方法はありますか?

これに取り組む方法についての他のアイデアはありますか?

1
John Bachir

Postgresはこのための演算子をサポートしていません。 @ evan-carrollによって指摘されたように、おそらく可能であり、そうすべきです。

したがって、最良の解決策は

where tsrange(localtimestamp, localtimestamp, '[]') >> tsrange(start_at, events.end_at, '[)')
1
John Bachir

現在の時刻が終了した後のイベントを照会したい。これを行う方法について私が知っている方法:

ここに要旨演算子 が表示されます。リストはrange_opsで確認できます。

&& &> &< >> << <@ -|- = @> @>

あなたがおそらく望むものは<<>>です。 <<を使用します。

醜いですか?はい。範囲タイプは、両側で範囲を操作する場合に最適ですが、ここではそうではありません。テーブルに範囲タイプを格納することすらありません。そうすることをお勧めします。

このインデックス条件が機能するかどうかはわかりませんが、

"my_idx" Gist (tsrange(start_at, end_at(events.*), '[)'::text))

あなたはそれをテストしましたか?つまり、PostgreSQLはstart_atが機能することを確認できますが、私の想定では、end_atevents.*で使用するのは十分スマートではありません(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();
0
Evan Carroll