PostgreSQLは,米California大学Berkley校で開発されたpostgresを源流とするオープンソースのDBMSである。ANSI SQL92に対応し,行ロック,読み取り一貫性,ストアド・プロシージャ,トリガーを実装するなど,商用DBMS製品に匹敵する機能を備える。このコラムでは,PostgreSQLの最新状況を報告していく。

 PostgreSQLは,現在次期バージョンである7.4のベータ・テストを実施している。8月27日にはベータ2がリリースされており,このまま順調にテストが進めばもう1,2回ほどベータ版がリリースされたのち,リリース・キャンディデート(リリース候補版)を経て正式リリースとなるはずである。どうやら年内にはPostgreSQL7.4の正式版が入手できそうだ。

 今回は,PostgreSQL7.4の主な特徴を概観してみる。

アーカイブ・ログからのデータベース復旧機能は見送り

 まず悪いニュースから。

 7.4で実装されることが期待されていたPoint In Time Recovery(PITR)は見送りになった。PITRとは,古くなったトランザクションログを保存しておき,万が一ディスク障害などでデータベースが破壊されたときにそこから復旧するというものだ。ほとんどの商用DBにはこの機能が付いているが,PITRがないPostgreSQLでは,こまめなバックアップや,レプリケーションで自衛する必要がある(この9月に発売されたばかりのPostgreSQL互換商用データベース「PowerGres Plus」では,アーカイブ・ログからのリカバリがサポートされている)。

VACUUMの自動実行などの新機能

 PITRという大物は追加されなかったが,いつものように,多数の細かな機能追加が行われている。PostgreSQLでは,データベースの不要領域を回収する「VACUUM」を行なわずに長期間運用すると,性能が低下する場合がある。7.4では,VACUUMを自動実行する機能pg_autovacuumが追加された。そのほか,主な追加機能を以下に示す。

・INFORMATION SCHEMAの追加
・読み取り専用トランザクション
・UPDATE ... SET col = DEFAULT のサポート
・LIMIT/OFFSETで定数だけでなく,式が指定可能になった
・ステートメント・レベルのトリガのサポート
・DOMAIN CHECK制約の追加
・ALTER DOMAIN, ALTER SEQUENCEの追加
・トランザクションの外側でもカーソルが使えるようになった
・TRUNCATEでトランザクションが有効になった
・新しい配列コンストラクタ「ARRAY」の導入

GROUP BYを含むSQL処理で2倍以上高速化

 7.4での性能改善を検証してみた。いくつかのSQLではっきりとわかる高速化が行われている。今回は,以下の環境でテストを行った。

ハードウェア: Let'S Note CF-W2, メモリ512MB
OS: Vine Linux 2.6
postgresql.confの設定: デフォルトのまま
PostgreSQLのバージョン: 7.3.4および2003年9月3日時点の開発中スナップショット(文中では「7.4」と表記)

 GROUP BYとは,ある基準に基づいて行をグループ分けするSQLの構文である。たとえば,

SELECT avg(年齢) FROM 住民年齢統計データ GROUP BY 県;

 などとすることによって,全国の住民の年齢統計データを県ごとにグループ分けし,県別に平均年齢を求めることができる。この例からもわかるように,GROUP BYは主に統計データや販売データなどの大量データの解析によく使われる重要なSQLの機能である。7.4ではこのGROUP BYが大幅に高速化された。

 ここではPostgreSQLに付属するベンチマークツールであるpgbenchで生成した10万件のデータを用いて同じSQL文を7.3.4と7.4で実行した結果を示す(試行は10回行い,最大値と最小値を除く8件のデータの平均値をとっている)。

SELECT count(*) FROM accounts GROUP BY bid;

7.3.4766.619ミリ秒
7.4326.205ミリ秒

 このように,2倍以上7.4の方が高速になっている。その理由を探るために,7.4で問い合わせ計画をEXPLAINを使って表示してみる。

test=# EXPLAIN SELECT count(*) FROM accounts GROUP BY bid;
QUERY PLAN
----------------------------------------------------------------------
HashAggregate (cost=3140.00..3140.00 rows=1 width=4)
-> Seq Scan on accounts (cost=0.00..2640.00 rows=100000 width=4)
(2 rows)

 「HashAggregate」というキーワードが目新しい。HashAggregateでは非常にコストの高いソート処理が不要になるため,その分高速になっているのである。

INサブクエリ(副問い合わせ)で6倍近く高速化

 GROUP BYよりもさらに高速化されたのが,SELECT ... WHERE col IN (1, 2,3...); のような形のIN副問い合わせである。ここでもpgbenchのデータを使ってSQL文を実行した結果を示す。

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

 これはINリストが1000個にもなる極端な例だが,データベース用のある種のアプリケーションはこのようなSQL文を自動生成することがある。実行時間は以下のようになった。

7.3.4平均 530.209ミリ秒
7.4平均 91.1188ミリ秒

 6倍近く7.4の方が速いという結果が出た。問い合わせプラン自体は7.3も7.4も変わらないが,7.4では,問い合わせ実行部(executor)により細かいチューニングが施された結果,高速化した。

WHERE節にSELECTを持つINサブクエリで600倍近い性能改善

 さらに劇的に高速化したのが,SELECT ... WHERE col IN (SELECT ...); のようなIN副問い合わせである。テストデータはやはりpgbenchのものを使用している。

SELECT count(*) FROM accounts WHERE aid IN (SELECT tid FROM tellers);

7.3.4平均 3108.87ミリ秒
7.4平均 5.22875ミリ秒

図1
図2
 実に600倍近い高速化である。このような場合,7.4では自動的に結合(JOIN)とほぼ同じ問い合わせプランで実行されるので,非常に効率がよくなる。このことはpostgresql.confで stats_row_level = true としてデータベースのアクセス統計を有効にしてみるとよくわかる。7.3ではtellersテーブルに100000回もアクセスしているのに対し,7.4では1回しかアクセスしていない(図1[拡大表示],図2[拡大表示])。

 もちろん7.3でも手動で

SELECT count(*) FROM accounts, tellers WHERE accounts.aid = tellers.tid;

のように問い合わせを書き換えれば一応高速化は可能である。しかし,いつもこのような書き換えができるとは限らないし,手動で問い合わせを書き換えるのは煩わしい作業である。7.4でこうした心配をする必要が減るのなら,まことにうれしい限りである。

手間いらず,手軽に使える高性能データベースを目指す

 PostgreSQL7.4は,新しい機能という点でははやや物足りないリリースではあるが「管理の手間がかからず,だれでも手軽に使える高性能データベース」という理想に着実に近づいている。商用DBによくある「ヒント句」のようなものには頼らず,どんなユーザでも高性能データベースの恩恵を受けることができるようにすべきであるというのがPostgreSQLの開発者の一貫した考え方だ。オープンソース・データベースらしい,こうした潔い姿勢を今後も貫いてほしい。

石井達夫(Tasuo Ishii)

■著者紹介
石井達夫(いしい・たつお)氏
1984年,SRA入社。主にUNIX関連の開発に従事するかたわら,95年からPostgreSQLのメーリング・リストを主宰。現在はオープンソースソリューション部でPostgreSQL関連のビジネス活動を技術支援。著書に『PostgreSQL完全攻略ガイド』(技術評論社),『PHPxPostgreSQLで作る最強Webシステム』(技術評論社),『PostgreSQL構築・運用ガイド』(日経BP,共著)などがある。日本PostgreSQLユーザ会理事長。