2010-11-08複数列の AND+OR 条件を 括弧+IN で

複数の列を AND 検索し、かつその条件が複数ある場合、普通は WHERE 句が (列1=... AND 列2=... AND ...) OR (...) と書くことが多いかと思いますが、実はこれを (列1, 列2, ...) IN ((...), ...) と書くこともできます。EXPLAIN を見ると、内部的には AND + OR の条件に展開されており、処理の効率には全く差はありません。インデックスも使えます。
=# CREATE TABLE tbl (a integer, b integer, c integer); =# INSERT INTO tbl SELECT i, j, k FROM (VALUES(1),(2),(3)) x(i), (VALUES(1),(2),(3)) y(j), (VALUES(1),(2),(3)) z(k); INSERT 0 27 =# CREATE INDEX idx ON tbl (a, b, c); =# SET enable_seqscan = off; =# EXPLAIN SELECT * FROM tbl WHERE (a,b,c) IN ((1,1,1), (2,2,2), (3,3,3)); QUERY PLAN ------------------------------------------------------------------------- Bitmap Heap Scan on tbl (cost=12.79..16.89 rows=3 width=12) Recheck Cond: (((a = 1) AND (b = 1) AND (c = 1)) OR ((a = 2) AND (b = 2) AND (c = 2)) OR ((a = 3) AND (b = 3) AND (c = 3))) -> BitmapOr (cost=12.79..12.79 rows=3 width=0) -> Bitmap Index Scan on idx (cost=0.00..4.26 rows=1 width=0) Index Cond: ((a = 1) AND (b = 1) AND (c = 1)) -> Bitmap Index Scan on idx (cost=0.00..4.26 rows=1 width=0) Index Cond: ((a = 2) AND (b = 2) AND (c = 2)) -> Bitmap Index Scan on idx (cost=0.00..4.26 rows=1 width=0) Index Cond: ((a = 3) AND (b = 3) AND (c = 3)) (9 rows)
このSQLは、構文的には行コンストラクタを使って、"ROW" を省略した形です。以下のように書いても全く同じように処理されます。
WHERE ROW(a,b,c) IN (ROW(1,1,1), ROW(2,2,2), ROW(3,3,3));
また、「列 IN (定数1, 定数2, ...)」と書く必要があると思い込んでいたんですが、逆にして「定数 IN (列1, 列2, ...)」でも問題無く動作するようです。
=# EXPLAIN SELECT * FROM tbl WHERE 3 IN (a, b, c); QUERY PLAN ------------------------------------------------------------------------ Bitmap Heap Scan on tbl (cost=21.24..25.71 rows=19 width=12) Recheck Cond: ((3 = a) OR (3 = b) OR (3 = c)) -> BitmapOr (cost=21.24..21.24 rows=27 width=0) -> Bitmap Index Scan on idx (cost=0.00..4.32 rows=9 width=0) Index Cond: (3 = a) -> Bitmap Index Scan on idx (cost=0.00..8.45 rows=9 width=0) Index Cond: (3 = b) -> Bitmap Index Scan on idx (cost=0.00..8.45 rows=9 width=0) Index Cond: (3 = c)
AND と OR で複雑になってしまった条件句は、IN を使うとスッキリ書けるかもしれませんね。
コメント