列starts_at
&ends_at
を使用して予約データを格納しているテーブルがあります。テーブルにクエリを実行して重複する予約を見つけるときはいつでも、次のクエリのいずれかを使用するオプションがあります。
SELECT * FROM reservations
WHERE starts_at < '2014-01-03 00:00:00'
AND ends_at >='2014-01-01 00:00:00';
または
SELECT * FROM reservations
WHERE tsrange(starts_at, ends_at) && ('2014-01-01 00:00:00', '2014-01-03 00:00:00')
starts_at
列とends_at
列に通常のBツリーインデックスがあるため、最初のクエリは常にそれらを使用しています。ただし、tsrangeで機能Gistインデックスを定義しない限り、2番目のクエリは完全なスキャンを実行します。
create index tsrange_idx on reservations using Gist(tsrange(starts_at, ends_at));
私の質問は、テーブルが大きくなるにつれて、どのインデックスが速くなるのですか?おそらく、答えはクエリ実行プランを見れば明らかですが、私はEXPLAIN ANALYZE
出力の読み取りに精通していません。
3番目のオプションをお勧めします。テーブルに2つのtimestamp
列が定義されている限り(これはNOT NULL
)単一の multicolumn index withopposedsort order(他の考慮事項が適用されない場合):
CREATE INDEX reservations_range_idx ON reservations using Gist(starts_at, ends_at DESC);
これらの関連する回答の詳細:
クエリについては、 SQL-標準演算子OVERLAPS
を見てください。
SELECT * FROM reservations
WHERE (starts_at, ends_at) OVERLAPS ('2014-01-01 00:00:00', '2014-01-03 00:00:00');
SOに関するこの関連質問の詳細:
2つのBツリーインデックスよりも高速である必要があります。ディスク容量が少なく、維持費が安くなります。書き込み操作の負担が少ない
大きなテーブルでは、 範囲型の要旨インデックス の方がスケールが優れているため、おそらく高速です。ただし、ディスク上のストレージはかなり大きく、インデックスのメンテナンスは少しコストがかかります。
そのルートを使用する場合は、タイムスタンプを範囲( tsrange
またはtstzrange
)として最初から格納する方が効率的です。機能的な側面がないプレーンなGistインデックスは少し高速です。
CREATE TABLE reservation (
reservation_id serial PRIMARY KEY
,span tsrange
, ...
);
CREATE INDEX reservation_span_Gist_idx on reservations USING Gist (span);
とともに - &&
"overlap" operator 既に質問に表示されています:
SELECT *
FROM reservation
WHERE span && ('2014-01-01 00:00:00', '2014-01-03 00:00:00');
また、除外制約に興味があるかもしれません。これは、上記のようなGistインデックスを自動的に実装する、設計によって重複を除外します。 マニュアルのコード例 があります。 SOに関するこの関連する回答には、より詳細があります: