Hatena::Grouppostgresql

PostgreSQL 雑記 このページをアンテナに追加 RSSフィード

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 を使うとスッキリ書けるかもしれませんね。