« Test::mysqldのcopy_data_fromでテストが更に捗る話 | メイン | Kyoto.pmに行ってきました »

2013年7月 9日

Teng::Plugin::SearchJoinedとSQL::Maker::JoinSelectとKyoto.pmの話

N+1問題という近年まことしやかに語られるようになった言葉があります。当たり前の事象に大げさに名前をつけるのどうなのかと思ったりもするわけですが、名前が付いていると案外説明に便利だったりして「名前重要」だなーとか思ったり思わなかったりするわけです。

最近はTengを便利に使わせてもらっているわけですが、Tengはシンプルな分、何も考えないで使うとN+1問題が多発してしまいます。そう言う思想なわけです。

クエリ数を抑えるためにJOINしたクエリを投げたくなるわけですが、そうなると自分で投げるしか無くて、それはまだいいとしても、普段Rowオブジェクトを使い慣れているゆるふわエンジニアとしては、JOINして複雑なデータを取った挙句、途端に生々しいハッシュを使わないといけないのはだいぶつらいものがあります。

ということで、

  • JOINしたクエリを分かりやすく記述できる
  • Rowオブジェクトをちゃんと取りたい

という目的をかなえるために、Teng::Plugin::SearchJoined というものをリリースしました。使い方はSYNOPSISとほぼ同じですが、以下の様な感じです。

package MyDB;
use parent qw/Teng/;
__PACKAGE__->load_plugin('SearchJoined');

package main;
my $teng = MyDB->new(...);
my $itr = $teng->search_joined(user_item => [
    user => {'user_item.user_id' => 'user.id'},
    item => {'user_item.item_id' => 'item.id'},
], {
    'user.id' => 2,
}, {
    order_by => 'user_item.item_id',
});

# $itr->suppress_object_creation(1); も可能
while (my ($user_item, $user, $item) = $itr->next) {
    ...
}

割と直感的でいいんじゃないかとおもいます。デフォルトINNER JOINですが各種JOINにも対応可能です。その辺りは、ドキュメントをご確認ください。

このプラグインはSQL::Maker::Plugin::JoinSelectというモジュールに依存しており、これもまた、SQL::MakerでJOINしたクエリを分かりやすく記述するために書いた拙作のモジュールです。

このモジュールを作るにあたっては、SQL::Makerに幾つか細かいp-rを送り付け、挙句一時的にTengをぶっ壊したりして大変ひどい感じだったのでした。いつもながらしょうもないp-rに素早く対応してくれるtokuhiromには感謝です。

今週末のKyoto.pmでトークさせていただくのですが、多分このへんの話をするんじゃないかと思います。

宿とか何も決めていないので誰か宿を提供してくださったりすると大変嬉しいです。ただし当方いびきがうるさいです。

あわせて読みたい。 http://blog.64p.org/entry/2013/07/09/114744

投稿者 Songmu : 2013年7月 9日 00:57