PostgreSQLスキルアップノート(自己啓発のための個人サイト)

ビットマップスキャン(ビットマップ走査計画型)


【一覧に戻る】
マニュアルへのリンクは/9.2/としています。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
■■■■ PostgreSQL スキルアップノート
■■■■
■◆■■ ビットマップスキャン(ビットマップ走査計画型)
■■■■
■■■■
■■■■ 使用環境:PostgreSQL9.2.3 (CentOS6.2)
         2013/03/20 
                                                                   (C) 2013 ohdb
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━


【マニュアル】

付録 E. リリースノート・リリース8.1→●[マニュアル]
第 11章インデックス−複数のインデックスの組み合わせ→●[マニュアル]

第18章サーバの設定− 問い合わせ計画−プランナメソッド設定
→●[マニュアル]


【マニュアル参考】
−

【その他】

ITPro 2005年当時の新機能紹介記事→●[記事]




■1■ 概要
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━


ビットマップスキャンはそれぞれのインデックスから行の物理位置の情報などを「ビットマップ」
としてメモリ上に展開しAND演算やOR演算で条件に該当する行の物理位置を求めそれを使ってヒープ
へアクセスするという高速なアクセス方法である。

付録 E. リリースノート・リリース8.1→●[マニュアル]
複数のインデックスの組み合わせ→●[マニュアル]


ビットマップスキャンの登場(8.1の時代)によって、2つのインデックスを同時に使うこと
ができるようになるなどPostgreSQLの問い合わせの性能が向上した。

なお、本ページでは2つのインデックスを同時に使う実行計画の例を取り上げているが、
ビットマップスキャンは常に2個のインデックスを使うという訳ではない。




■2■  簡単な実行計画確認・準備
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

本ページで使うデータを作成する。

テーブル作成、ランダムデータ生成&100万件データ挿入、プライマリキー作成、インデックス作成、
バキューム、アナライズ、EXPLAINの準備、をまとめて行う。


【□】 以下をまとめて一度にコピー&ペーストで実行する

┌────────────────────────────┐

-- ここから ------
-- t1テーブル削除・再作成
DROP TABLE t1;
CREATE TABLE t1 (c1 integer NOT NULL,c2 char(3) NOT NULL,c3 integer NOT NULL,c4 text) WITH (FILLFACTOR=90);
-- ランダムデータ生成・指定した数値範囲
\set nm1 1
\set nm2 1000
\set nm 'floor(:nm1+random()*(:nm2+1-:nm1))' 
-- ランダムデータ生成・英字(大文字)
\set au 'chr(floor(65+random()*(90+1-65))::int)'
\set au3 :au||:au||:au
\set au6 :au||:au||:au||:au||:au||:au
-- データ100万件インサート
-- \set fetch_count 10000
\timing on \pset pager off 
INSERT INTO t1 SELECT generate_series(1,1000000),:au3,:nm*100,:au6;
-- プライマリ・インデックス・バキュームアナライズ
ALTER TABLE t1 ADD PRIMARY KEY (c1);
CREATE INDEX t1_c2c3_idx ON t1(c2,c3);
VACUUM ANALYZE t1;
-- テーブルサンプル表示・件数カウント
\d+ t1
\echo データ件数
SELECT COUNT(*) FROM t1;
\echo データ内容サンプル(先頭の5件)
SELECT * FROM t1 LIMIT 5;
-- EXPLAIN準備
\set ep1 'EXPLAIN (ANALYZE,VERBOSE,BUFFERS)'
\set ep2 'EXPLAIN ANALYZE'
-- ここまで ------

└────────────────────────────┘



実行計画の確認は、以降では

  :ep1 SQL文;  あるいは
  :ep2 SQL文;

のようにして確認することができます。
:ep1や:ep2の内容は上のスクリプトで確認できます。
EXPLAIN (ANALYZE,VERBOSE,BUFFERS) などの記法は、バッファなどより詳細な情報を
取得する指定で、カッコとともに使います。(9.0以降)




■3■ ビットマップスキャンで複数インデックスを同時に使用
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

以下の例は、2個のインデックスを同時に使う典型的なビットマップスキャンの例。
ただ、常に2個のインデックスを使う訳ではなく、日常的には1個だけのビットマップスキャンの方がよく発生する。


以下の実行計画は2個のインデックスの同時アクセスが行われる例となっているが、実行計画は
条件値の与え方ひとつで変わってしまい、うまく再現できないかもしれない。
そのような場合はそれぞれの条件値を変えて試行する必要がある。


【□】 :ep1 SELECT c1,c2 FROM t1 where c1 < 100001 AND c2 like 'AA%';
【□】 :ep1 SELECT c1,c2 FROM t1 where c1 < 100001 OR c2 like 'AA%';


database1=# :ep1 SELECT c1,c2 FROM t1 where c1 < 100001 AND c2 like 'AA%';
                                                             QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------
★Bitmap Heap Scan on public.t1  (cost=1918.65..2468.90 rows=30 width=8) (actual time=14.414..14.628 rows=128 loops=1)
   Output: c1, c2
   Recheck Cond: (t1.c1 < 100001)
   Filter: (t1.c2 ~~ 'AA%'::text)
   Buffers: shared hit=405
   ->★BitmapAnd  (cost=1918.65..1918.65 rows=155 width=0) (actual time=14.347..14.347 rows=0 loops=1)
         Buffers: shared hit=283
         ->★Bitmap Index Scan on t1_c2c3_idx  (cost=0.00..35.61 rows=1525 width=0) (actual time=0.626..0.626 rows=1495 loops=1)
               Index Cond: ((t1.c2 >= 'AA'::bpchar) AND (t1.c2 < 'AB'::bpchar))
               Buffers: shared hit=7
         ->★Bitmap Index Scan on t1_pkey  (cost=0.00..1882.77 rows=101655 width=0) (actual time=13.470..13.470 rows=100000 loops=1)
               Index Cond: (t1.c1 < 100001)
               Buffers: shared hit=276
 Total runtime: 14.716 ms


database1=# :ep1 SELECT c1,c2 FROM t1 where c1 < 100001 OR c2 like 'AA%';
                                                             QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------
★Bitmap Heap Scan on public.t1  (cost=1969.34..10610.04 rows=101923 width=8) (actual time=11.108..51.595 rows=101367 loops=1)
   Output: c1, c2
   Recheck Cond: ((t1.c1 < 100001) OR (t1.c2 ~~ 'AA%'::text))
   Filter: ((t1.c1 < 100001) OR (t1.c2 ~~ 'AA%'::text))
   Buffers: shared hit=1622 read=587
   ->★BitmapOr  (cost=1969.34..1969.34 rows=103180 width=0) (actual time=10.792..10.792 rows=0 loops=1)
         Buffers: shared hit=283
         ->★Bitmap Index Scan on t1_pkey  (cost=0.00..1882.77 rows=101655 width=0) (actual time=10.338..10.338 rows=100000 loops=1)
               Index Cond: (t1.c1 < 100001)
               Buffers: shared hit=276
         ->★Bitmap Index Scan on t1_c2c3_idx  (cost=0.00..35.61 rows=1525 width=0) (actual time=0.451..0.451 rows=1495 loops=1)
               Index Cond: ((t1.c2 >= 'AA'::bpchar) AND (t1.c2 < 'AB'::bpchar))
               Buffers: shared hit=7
 Total runtime: 72.483 ms




・・・・上の2つの例ではt1_pkeyとt1_c2c3_idxに対してそれぞれ「Bitmap Index Scan」を行い、
        それをもとにAnd(またはOr)演算(BitmapAnd/BitmapOr)をし、ここで得られた行の物理位置
        を使って、t1テーブルへアクセス(Bitmap Heap Scan)をしている。






以上 
inserted by FC2 system