前回は開発中のPostgreSQL 8.1で,バッファ・マネージャに改良が加えられて,大幅な性能向上があったことを述べた。今回は同じく性能面で大きな前進となるビットマップ・ベースの実行プラン・タイプが追加されたことを報告する。なお,本稿で検証に使用したのは5月3日時点のバージョンである。
オプティマイザと実行プラン
その前に,PostgreSQLにおけるオプティマイザと実行プランについて復習しておこう。
テーブルにはアクセスを高速化するためにインデックスを追加することができる。インデックスとは日本語で「索引」のことである。例えば書籍を例にとって考えてみよう。ある書籍の中から,「神奈川県」について書かれたページを探したいとする。もし索引がなければ書籍の1ページ目から丹念に読んでいくしかない。しかし索引があれば,「神奈川県」について書かれたページがすぐに分かるので,素早く目的のページにたどり着くことができる。
PostgreSQLのインデックスも発想は同じである。あるテーブルのある列にインデックスを設定すると,インデックスの中には「列の値と行の物理的な位置」のペアが行数分だけ作成される。「行の物理的な位置」は「TID」(Tuple ID)と呼ばれる形式で格納され,実際には「テーブル・ファイルのブロック番号+その中のオフセット位置」で表現される。つまり,ページがわかれば書籍の該当ヶ所がすぐ分かるように,TIDがわかれば素早く行にアクセスすることができるのである。もしインデックスがなければ,テーブル・ファイルを頭から順に読む以外に目的の行に到達する方法がなく,インデックスを使った場合に比べて比較にならないほど時間がかかる。
ただし,中にはインデックスを使わない方がよいケースもある。例えば,
SELECT * FROM t1;
のように,テーブルの全件もしくは大半を検索するような問い合わせではインデックスを使わない。問い合わせ結果を作成するためにはどのみちテーブル・ファイルの大半を読まなければならず,インデックス検索するだけ無駄であるからである。
PostgreSQLのオプティマイザは,こうした諸条件を考慮して最も効率がよいと思われる方法(実行プラン)を選択する。実行プランはあらかじめ用意された様々なプラン・タイプを組み合わせたものである。表1に主なプラン・タイプの一覧を示す。
表1●主なプラン・タイプ
順スキャン | テーブル・ファイルを頭から順にスキャン |
インデックス・スキャン | インデックスを使ってスキャン |
ネステッド・ループ結合 | 2つのテーブルを行単位で逐次比較 |
ハッシュジョイン結合 | ハッシュ表を作成しておいてから2つのテーブルを結合 |
マージ結合 | 2つのテーブルをソートしておいてから(もしくはBtreeインデックスを使って)結合 |
ハッシュ・アグリゲート | ハッシュ表を作成してから集約関数を実行 |
グループ・アグリゲート | ソートしてから集約関数を実行 |
新しく追加されたプラン・タイプ
今回追加されたのはビットマップを使用する新しいプラン・タイプである(表2)。
表2●追加されたプラン・タイプ
ビットマップ・インデックス・スキャン | インデックスを検索して条件を満たすTIDをビットマップとして生成する |
ビットマップAND | ビットマップを使ってAND条件を計算する |
ビットマップOR | ビットマップを使ってOR条件を計算する |
ビットマップ・ヒープ・スキャン | TIDビットマップを使ってテーブル・ファイルを検索する |
これらのプラン・タイプが実際にどのように利用されるのか,またどのような効果を上げるのかを見ていこう。