クエリの無駄とかチューニングとか
mysqlとかのRDBMSってノリと雰囲気と勢いで使ってるので つまりよく知らずに使ってます。
1件取得
例えばこんなスキーマから
mysql> desc guest2site; +------------+----------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+----------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | guest_id | int(11) | YES | MUL | NULL | | | site_id | int(11) | YES | MUL | NULL | | | created_at | datetime | YES | | NULL | | | updated_at | datetime | YES | | NULL | | +------------+----------+------+-----+---------+----------------+
guest_id=2 なデータが1件欲しいとき、前はこうしていた。
my $d = Guest2Site->search({guest_id => 2})->next;
吐かれるクエリは
SELECT guest2site.id, guest2site.guest_id, guest2site.site_id, guest2site.created_at, guest2site.updated_at FROM guest2site WHERE (guest2site.guest_id = ?) [ 2 ]
まぁ欲しい値は取れる。が。
ボス「それ guest_id=2 なデータを全部fetchして1件だけ使って残りは捨ててるから凄い無駄だよ」
へぶし。前職で書いた某webアプリは毎日無駄なクエリを吐いてましたごめんなさい。
物凄い勢いで書き直すべきだと思います。いや負荷ないならどーでもいいけど。
さておきんじゃどーするのっと言うと、クエリに limit 1 が付くように書きましょう。
my $d = Guest2Site->search({guest_id => 2}, {limit => 1})->next;
あと余談。この書き方だと
- iterator object作成
- そこからrow object作成
という手順を踏む。大抵はiterator objectは不要だろう。なのでコード的な意味でチューニングするなら、fetchの受け取りコンテキストをarrayにして返り値の1個目を直接取得して、iterator objectを作らないようにする。
ページング
をやるとき、前はこうしていた。
# コードはイメージです my $page = param('page') || 1; my $offset = ($page == 1) ? 0 : $page * 10 - 10; my $data = Table->search( {}, { sort => "column", direction => "descend", limit => 10, offset => $offset, } );
これも
ボス「それ例えばidが9990〜10000のデータ取るとき、10000件ソートしてfetchして9990件捨ててるから凄い無駄だよ」
ごめんなさいすいません申し訳ございません知りませんでした。
すげー無駄ですね。
んじゃどーするのと言うと。
「このidからidが大きい方に10件fetchする」だそうで。
それは書ける。が、ページングのリンクどう書こう。nextの方は p=40 とかでいいけど、previousな方は p=-40 とかにしてモデル側で判別か?そもメソッド分ける?まあどうとでもなるか。
どうでもいいけどDBICの $data->pager がカスなのは周知なので使ってる人は最早どこにも居るわけがない。
later
こーいう常識他にも色々知らないんだけどどこで学べばいーのかな。本か?