ケースを単純化するために、次の 3 つのテーブルがあるとします。
A(a_id)、B(b_id、val_b)、C(a_id、b_id、val_c)
B と C から特定の値のペアを持つすべての a_id を見つける必要があります。 ' および val_c='4' および B.b_id=C.b_id) AND ...
select A.a_id
from A
where (A.a_id in
(select C.a_id
from B, C
where B.b_id=C.b_id and B.val_b='1' and C.val_c='2') and
A.a_id in
(select C.a_id
from B, C
where B.b_id=C.b_id and B.val_b='3' and C.val_c='4') and
A.a_id in
(select C.a_id
from B, C
where B.b_id=C.b_id and B.val_b='5' and C.val_c='6'));
私が気付いたのは、(val_b,val_c) ペアをさらにいくつか追加すると、postgres がクエリを実行するのにかなりの時間がかかることです。ID、val_b および val_c のインデックスが存在することに注意してください。
クエリを最適化する方法はありますか? 明示的な内部結合を試みましたが、パフォーマンスの向上には役立ちませんでした。
前もって感謝します
より詳しい情報:
- postgres バージョン 8.2.4
- ペア基準が 1 つだけの場合、77.621 ミリ秒で実行されます
- 2 ペア基準の場合 - 151.588 ミリ秒
3 組の基準 - 49483.979 ミリ秒 <-- パフォーマンスが狂ったように火花を散らす
別のサブクエリ自体は最大 62 ミリ秒で実行されることに注意してください。
アップデート:
Vladimir Baranov によって以下に提案された個別の INTERSECT クエリ バージョンと、Clodoaldo Neto によって bool_or 集計関数を使用する has 句を含むバージョンの両方が、はるかに優れたパフォーマンスを発揮しました。ありがとうございました !
ただし、postgres 8.2 が 3 つのペア基準で始まる元のクエリでパフォーマンスが向上する理由は何ですか?
ところで、Vladimir Baranov の最初の提案で、クエリをクリーン ジョインで書き直すという同じ火花に気付きました。下記参照:
SELECT A.a_id
FROM
A
INNER JOIN (SELECT C.a_id FROM B INNER JOIN C ON B.b_id=C.b_id WHERE B.val_b='1' and C.val_c='2') Set1 ON Set1.a_id = A.a_id
INNER JOIN (SELECT C.a_id FROM B INNER JOIN C ON B.b_id=C.b_id WHERE B.val_b='3' and C.val_c='4') Set2 ON Set2.a_id = A.a_id
INNER JOIN (SELECT C.a_id FROM B INNER JOIN C ON B.b_id=C.b_id WHERE B.val_b='5' and C.val_c='6') Set3 ON Set3.a_id = A.a_id
;
3 セットのクエリは非常に高速に実行されますが、別の 3 ~ 4 セットを追加するとすぐに、クエリのパフォーマンスが 30 ~ 40 秒に低下します。