クエリダンプについてB!

こんにちわ! yappo です!

十日目は Data::Model での SQL プロファイリングにつての考察です。

Data::Model では、もともと単純なクエリを吐いて使うことを想定しているので難しいクエリの最適化なんか考える場面は少ないです。

複雑なクエリ履きたいなら、そもそも ORM のレイヤなんか生でやればいいじゃんどうでもいいよという事です。

そんな酔っぱらいの yappo はどうでもいいです。

という冗談はさておき、生 DBI で 生 SQL を書く場合は、クエリの最適化を行うのは用意ですね。

$dbh->prepare('SELECT * FROM user');

と、SQLがみえてるので、ちゃちゃっと print debug などをかければいいと思います。

問題は、通常のメソッドや Data::Model::SQL で生成したクエリのダンプを取りたいとき、 bind 値を見たい時ですが Data::Model では、発行しているクエリの内容を出力するために便利なフックポイントがあります。

Data::Model::Driver::DBI に start_query というメソッドが生えており、 Data::Model の内部でクエリを発行するときに、発行する SQL と bind された値を引数にして呼び出しています。

昨日の mixin の実装で

        $driver->start_query($sql, $sql_obj->bind); # クエリログ用

と記述して特に説明をしていないメソッドがそれです。

実際は以下のように記述します。

{
    package Data::Model::Driver::DBI;

    no warnings 'redefine';
    sub start_query {
        my($self, $sql, $bind) = @_;
        my $params;
        if (ref($bind) eq 'HASH') {
            # insert or replace
            $params = join ', ', map { "$_ => $bind->{$_}" } keys %{ $bind };
        } elsif (ref($bind) eq 'ARRAY') {
            # select or update or delete
            $params = join ', ', @{ $bind };
        }

        print "--- QUERY DUMP START
SQL : $sql
BIND: $params
--- QUERY DUMP END
";
    }
}

現在の仕様では、 update クエリのみが { column_name => value } という HASH リファレンスが $bind に入ります。

それ以外のクエリでは、 bind された値が順番に ARRAY リファレンスとして格納されます。

ここの仕様は将来的に若干変更される予定です。

このコードを有効にした状態で下記のコードを実行します。

my $bookmark = MyBookmark->new;
$bookmark->set(
    user => 1 => { nickname => 'Yappo' }
);
my $row = $bookmark->lookup( user => 1 );
$row->nickname('takefumi');
$row->update;
$row->delete;

すると以下のように出力されます。

--- QUERY DUMP START
SQL : INSERT INTO user
(nickname, id)
VALUES (?, ?)

BIND: nickname => Yappo, id => 1
--- QUERY DUMP END
--- QUERY DUMP START
SQL : SELECT id, nickname
FROM user
WHERE (id = ?)

BIND: 1
--- QUERY DUMP END
--- QUERY DUMP START
SQL : UPDATE user SET nickname = ? WHERE (id = ?)

BIND: takefumi, 1
--- QUERY DUMP END
--- QUERY DUMP START
SQL : DELETE FROM user
WHERE (id = ?)

BIND: 1
--- QUERY DUMP END

発行したSQLとbindした値が一緒にでます。

こうすればどのようなSQLを実際に実行したのかわかるようになるので、デバッグしやすいですね!

have a nice data-model days!:)