PostgreSQLでは,postgresql.confを設定することにより,SQL文やその実行時間などの情報をログファイルに記録できる。ここではこのログのことを「SQLログ」と呼ぶことにしよう。単に「ログ」というと,トランザクションログ(WALログ)と混同する恐れがあるからである。

SQLログには以下のような記録が残る。

LOG: statement: INSERT INTO history (tid,bid,aid,delta,mtime) VALUES (4,1,25891,8417,CURRENT_TIMESTAMP);
LOG: duration: 72.786 ms

 ここから,このINSERT文の実行には72ミリ秒ほどかかっていることが分かる。これを利用すると,性能的にボトルネックになっているSQL文を見つけることもできる。

pgFouineとは


写真1●pgFouineのWebサイト
[画像のクリックで拡大表示]
 しかし,SQLログはテキスト形式で情報が羅列されているだけであり,解読には手間がかかる。また遅いSQLを探すためには,SQLログをツールを使って統計処理するなどの必要もある。

 そこで開発されたのがpgFouineだ。pgFouineを使えばSQLログを素早く解析し,レポートを作成できる。結果をグラフを交えてビジュアルに表示することも可能だ(写真1)。

 ちなみにFounieはフランス語で貂(テン)を意味する。作者はフランスのリオン在住,弱冠25才のGuillaume Smet氏だ。開発はpgpool同様,pgfoundry.orgでホスティングされており,http://pgfouine.projects.postgresql.org/ で開発サイトにアクセスできる。

インストール

 評価に使ったのは本稿執筆時点で最新版のバージョン0.5である。以下からダウンロードできる。

http://pgfoundry.org/frs/download.php/828/pgfouine-0.5.tar.gz

 インストールは極めて容易で,単に好みの場所にtar ballを展開するだけだ。展開すると,以下のようなファイルやディレクトリができる。

AUTHORS ChangeLog README include/ pgfouine.spec tests/
COPYING INSTALL THANKS pgfouine.php* rpm-specific/

 pgfouine.php がツール本体で,PHPで書かれたスクリプトになっている。したがって実行にはPHPが必要だ。評価に使ったのはPHP 4.4.2だが,PHP 5.1でも使えるとのことだ。

 このファイルの冒頭には

#! /usr/bin/php -qC

のようにphpコマンドへのパスが埋め込まれている。/usr/bin/以外のところにPHPをインストールしている場合はここを修正する。筆者はソースからPHPをインストールしているので,ここを

#! /usr/local/bin/php -qC

と書き換えた。

 pgfouineでは,グラフを描画するためにGDを使っており,PHPを作成する際にGDのサポートを有効にする必要がある。このため,PHP 4.4.2を作成する際に筆者は以下のようにconfigureのオプションを指定した。

# ./configure --without-mysql --with-apxs=/usr/local/apache/bin/apxs \
--enable-mbstring --enable-mbregex --with-pgsql --with-zlib \
--with-gd --with-jpeg-dir=/usr/lib --with-xpm-dir=/usr/lib \
--with-freetype-dir=/usr/lib --enable-gd-native-ttf --enable-gd-jis-conv

pgFouineのオプション

 pgFouineはPostgreSQLのログを解析,その結果をファイルに出力する。詳細はコマンドオプションで指定する。主なオプションを説明する。

表1●pgFouineのコマンド・オプション

-file 解析対象のログファイル名。「-」を指定すると標準入力からログを読み込む。
-format 出力フォーマット。text,html,html-with-graphs の中から選ぶ。省略すると html になる。
-report [outputfile=] 出力ファイルをoutfileで指定する。block1,block2...はレポートのタイプであり,複数のレポートを同時に指定できる。レポートのタイプについては別途解説する。
-from "" これより前の日付のログを無視する
-to "" これより後の日付のログを無視する

pgFouineが解析できるログのフォーマット

 pgFouineの解析できるログのフォーマットは今のところsyslogへの出力だけである。しかし,syslogへログを大量に出力すると,深刻なシステムのパフォーマンス低下をもたらす。そこで筆者はpgFouineにパッチを当て,ファイルへのログ出力をサポートできるようにした。

*** include/postgresql/parsers/SyslogPostgreSQLParser.class.php.orig 2006-04-16 22:01:41.000000000 +0900
--- include/postgresql/parsers/SyslogPostgreSQLParser.class.php 2006-04-01 23:09:07.000000000 +0900
***************
*** 25,31 ****
var $regexpPostgresPid;

function SyslogPostgreSQLParser($syslogString = 'postgres') {
! $this->regexpSyslogContext = new RegExp('/^([A-Z][a-z]{2} [ 0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}) .*? '.$syslogString.'\[(\d{1,5})\]: \[(\d{1,20})(?:\-(\d{1,5}))?\] /');
}

function & parse($data) {
--- 25,32 ----
var $regexpPostgresPid;

function SyslogPostgreSQLParser($syslogString = 'postgres') {
! // $this->regexpSyslogContext = new RegExp('/^([A-Z][a-z]{2} [ 0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}) .*? '.$syslogString.'\[(\d{1,5})\]: \[(\d{1,20})(?:\-(\d{1,5}))?\] /');
! $this->regexpSyslogContext = new RegExp('/^([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} JST) .*? '.$syslogString.'\[(\d{1,5})\]: \[(\d{1,10})(?:\-(\d{1,5}))?\] /');
}

function & parse($data) {

 そして,postgresql.confを以下のように修正する(PostgreSQL 8.1の場合)。

log_destination = 'stderr'
redirect_stderr = on
log_duration = on
log_statement = 'all'
log_line_prefix = '%t myhost postgres[%p]: [%l-1] '

 これで後はしばらくPostgreSQLを動かし,ログを収集する。