非同期クエリ考察結果

※2010/03/05追記
 ちょっとスクリプト変えた






id:sfujiwaraさんの記事を参考にDBD::Pgによる投げっぱなし非同期クエリを試してみた。
http://d.hatena.ne.jp/sfujiwara/20100225/1267075758


いろいろ試してみておおむね問題ないが、
SQLで発生した内部エラーはキャッチすることが出来ないらしい。
ちなみに構文エラーは大丈夫。

テスト用テーブル作成

col2に必須制約を付けてる。

create table test
(
    col1 text,
    col2 text not null
);

構文エラーバージョン

スクリプト

use DBI;
use DBD::Pg ":async";

my $dbh    = DBI->connect("dbi:Pg:dbname=postgres", "", "", { AutoCommit => 1});
my $sth = $dbh->prepare( "INSERT INTO test(col1) VALUES(aaaaaaaa) ", { pg_async => PG_ASYNC }, );
$sth->execute();
$dbh->disconnect;

結果

$ perl pgsql1.pl 
DBD::Pg::st execute failed: ERROR:  column "aaaaaaaa" does not exist
LINE 1: INSERT INTO test(col1) VALUES(aaaaaaaa) 
                                      ^ at pgsql1.pl line 10.

エラーが返ってくる。

内部エラーバージョン(NOT NULL制約でエラーになるはず)

スクリプト

use DBI;
use DBD::Pg ":async";

my $dbh    = DBI->connect(dbi:Pg:dbname=postgres, "", "", { AutoCommit => 1});
my $sth = $dbh->prepare( "INSERT INTO test(col1) VALUES('hoge') ", { pg_async => PG_ASYNC }, );
$sth->execute();
$dbh->disconnect;

結果

$ perl pgsql2.pl 
$ 

何も返ってこない。



内部エラーバージョン(sleepして最大0.03秒まで待つ)

use DBI;
use DBD::Pg ":async";
use Time::HiRes 'sleep';

my $dbh    = DBI->connect( "dbi:Pg:dbname=postgres", "", "", { AutoCommit => 1, });
my $sth = $dbh->prepare( "INSERT INTO test(col1) VALUES('hoge') ", { pg_async => PG_ASYNC }, );
$sth->execute();

my $res;
my $counter = 0;
while (1) {
    if ( $dbh->pg_ready() ) {
        $res = $dbh->pg_result();
        print "Result of do(): $res\n";
        last;
    }
    print "Query is still running...\n";
    sleep( 0.001 );
    last if $counter > 30;
    $counter++;
}
$dbh->disconnect;

結果

$ perl pgsql3.pl 
Query is still running...
DBD::Pg::db pg_result failed: ERROR:  null value in column "col2" violates not-null constraint at pgsql3.pl line 17.
Result of do(): 

1回目で返ってくる。
環境にもよるけど、0.5秒くらいにしておけば大抵キャッチ出来るかな?
確実にエラーを取得したいなら、postgresのログを見るとかでもいいか。

2010/3/5 追記

selectをTime::HiRes::sleepに変更。理由は後日。

あとsleepを「0.1」→「0.001」に変更し、counterの値も調整。
というのも上記コードで0.1にしておくと必ず0.1秒待ってしまうというhogeなコードになってしまっていたので、0.001にした。*1
これだとパフォーマンスにも影響しなさそうだしエラーもキャッチできてていい感じ。

*1:apacheベンチで全然パフォーマンス出なくて気付いたという