2006年12月5日,PostgreSQL 8.2が正式リリースされた。8.2の機能については既にこの連載でも何度か取り上げているが,今回はまだ説明していなかったものの中から面白そうなものをご紹介しよう。

IN問い合わせの改良

SELECT ... WHERE foo IN (1,2,3...);

のように,多くの項目を問い合わせるようなIN問い合わせが改良され,性能が上した。このような問い合わせは機械的にツールで生成した問い合わせに見られることがある。従来のバージョンでは項目の数が増えると急激に性能が劣化していた。

 例えば,pgbench で生成されるデータを使った以下のような問い合わせでは,次のようなプランが生成される。

SELECT count(*) FROM accounts WHERE aid IN (1,2,3);

                              QUERY PLAN                                   
---------------------------------------------------------------------------
Aggregate  (cost=17.68..17.69 rows=1 width=0)
 ->  Bitmap Heap Scan on accounts  (cost=6.01..17.67 rows=3 width=0)
  Recheck Cond: ((aid = 1) OR (aid = 2) OR (aid = 3))
  ->  BitmapOr  (cost=6.01..6.01 rows=3 width=0)
   ->  Bitmap Index Scan on accounts_pkey  (cost=0.00..2.00 rows=1 width=0)
         Index Cond: (aid = 1)
   ->  Bitmap Index Scan on accounts_pkey  (cost=0.00..2.00 rows=1 width=0)
         Index Cond: (aid = 2)
   ->  Bitmap Index Scan on accounts_pkey  (cost=0.00..2.00 rows=1 width=0)
         Index Cond: (aid = 3)
(10 rows)

 このプランでは,IN項目の数分だけインデックスをアクセスしなければならない。

 それに対して,8.2では以下のようなプランになる。

                              QUERY PLAN                                   
---------------------------------------------------------------------------
Aggregate  (cost=23.68..23.69 rows=1 width=0)
 ->  Bitmap Heap Scan on accounts  (cost=12.02..23.67 rows=3 width=0)
  Recheck Cond: (aid = ANY ('{1,2,3}'::integer[]))
  ->  Bitmap Index Scan on accounts_pkey  (cost=0.00..12.02 rows=3 width=0)
        Index Cond: (aid = ANY ('{1,2,3}'::integer[]))
(5 rows)

 IN項目でいったん配列を作り,インデックスへのアクセスを一度で済ませているために,効率がよい。

 この改良でどの程度性能が向上したのかを検証するためにベンチマークテストを行ってみた。