日時フィールドstart
およびend
のテーブルがあります。 (スタート、エンド)アイテムのリストがあります。リストのどのアイテムがテーブルのデータと重複しているかを確認する必要があります。現在のクエリは次のようになります。
select br.duration from booking, (
select tstzrange('2016-09-06 03:45:00+00', '2016-09-06 14:45:00+00') as duration
union select tstzrange('2016-09-06 14:45:00+00', '2016-09-06 15:45:00+00') as duration
-- other items from my list
) as br
where tstzrange(start, end) && br.duration
それを行う他の方法はありますか?テーブルに数百万の行があり、それらをリストの数百のアイテムと比較すると、うまくいくと思いますか?
100万行を処理するためのいくつかの重要な改善を提案します。
_SELECT br.duration
FROM (
VALUES
('[2016-09-06 03:45:00+00, 2016-09-06 14:45:00+00)'::tstzrange)
, ('[2016-09-06 14:45:00+00, 2016-09-06 15:45:00+00)')
-- more items
) br(duration)
WHERE EXISTS (
SELECT FROM booking
WHERE tstzrange(ts_start, ts_end) && br.duration
);
_
値のリストに不必要に冗長で高価な形式_SELECT ... UNION ...
_を提供しながら、それを_UNION ALL
_にしてください。そうしないと、Postgresが重複を折り畳むために時間を浪費します。また、SELECT
クエリの最初のUNION
の列名とデータ型を宣言するだけで済みます。
しかし、VALUES
式の方が単純で高速です。または、配列_tstzrange[]
_を提供し、unnest()
を使用します。
クエリは、booking
の重複する行ごとに1行を返しますが、おそらくリストから重複する各値onceが必要になる可能性があります。 DISTINCT
または_GROUP BY
_を追加して一意の行を取得することもできますが、それでも時間の無駄になります。 EXISTS
セミジョインは、ケースの非常にシンプルで安価な代替手段の1つです:duration
の各行重複するエントリが見つかった場合に1回だけ返され、Postgresはこの行の検索を停止できます。
インデックスのサポートがないと、クエリはまだ遅くなります。機能的な要旨または SP-Gist index を作成します。後者はおそらく最高のパフォーマンスを発揮します。
_CREATE INDEX booking_ts_range_idx on booking USING spgist (tstzrange(ts_start, ts_end));
_
関連: