待望のPostgreSQL 8.0のリリースが間近に迫っている。そこで今回は,以前PostgreSQL 8.0を取り上げたときに詳しく紹介できなかったオプティマイザの改良個所を説明したい。

 なお,PostgreSQL 8.0は本稿執筆時点でベータテスト中であり,検証のために7.4系,8.0系でそれぞれ以下の最新バージョンを使用した。

7.4系: PostgreSQL 7.4.6
8.0系: PostgreSQL 8.0 beta5

オプティマイザとは

 「オプティマイザ」とは,正確には「クエリ・オプティマイザ(query optimizer)」のことであり,ユーザーから受け取ったSQLの実行を最適化する機能のことである。

 例えばあるテーブルからデータを抽出する以下のようなSQL文を考える。

SELECT * FROM t1 WHERE i = 100;
 テーブルt1のi列にはインデックスが設定されているとする。この問い合わせを最も早く実行する方法はどのようなものであろうか?ちょっと考えると,インデックスを検索するのが一番早いような気がするが,いつもそうであるとは限らない。例えば,以下のような場合にはインデックスを使わない方が早いのである。

(1) テーブルが小さい場合

(2) WHERE句の条件に該当する行が非常に多い場合

 これが複数のテーブルが結合されるようなケースではさらに事態が複雑になる。PostgreSQLはテーブルを結合する方法を3種類サポートしている。テーブルの結合方法を複数用意しているのは,どれも得意不得意があり,一概にどれがもっとも高性能,とは言えないからだ。

(1) 入れ子結合方式(nested loop join)は,データが小さい場合に向いている

(2) マージ・ジョイン(merge join)方式は,データ量が多い場合に向いている

(3) ソートメモリーが十分にある場合はハッシュ・ジョイン(hash join)が早い

 さらに,テーブルの結合順を変えると処理速度が大幅に変わるので,それも考慮しなければならない。

 また,問い合わせをそのまま実行するのではなく,形を変えて実行する場合もある。例えばPostgreSQLはある種の副問い合わせを使った問い合わせを,より効率の良い結合を使った問い合わせに書き換えてから実行する。

 これらほんの一例に過ぎないが,問い合わせの最適化が複雑な作業であることはおわかりいただけたと思う。オプティマイザのできによってDBMSの性能が非常に大きな影響を受けることも容易に想像がつく。

 もちろんオプティマイザも完璧ではないから,最適化できない問い合わせも存在する。このような場合はPostgreSQLではある程度手動で最適なプランを選ぶように設定することもできるが,このためには高度な知識が必要だし,手間もかかる。できるだけオプティマイザが自動的に最適化してくれることが望ましいと言える。

 オプティマイザの改良は外からは見えにくい地味な部分だが,その性能によって問い合わせの実行速度が数倍,ときには数百倍も違ってくることがあり,実用上は非常に重要なポイントである。PostgreSQLの開発者もその重要性を十分認識しており,リリースのたびに改良が加えられている。本稿ではそれを取り上げていく。