recursive設定によるfind()性能改善

CakePHPでは、モデルにアソシエーションを設定している場合、recursive(=>joinする階層)はデフォルトで0に設定されています。「recursiveゼロ」の意味するところとは、「1跨ぎまでのJoinを行う」ということになり、Find()関数を使用した場合、デフォルトの状態でJoinが行われてしまいます。テーブル単体でfindしたい場合などは、find()の前に$recursive = -1とすることで余計なjoin処理を省略することができます。join先のテーブルのレコード数が多い場合などは効果絶大。

「User」とそれに紐付く「Usercomment」モデルを用意しました。

-- usersテーブル
CREATE  TABLE IF NOT EXISTS `users` (
    `id` INT NOT NULL AUTO_INCREMENT ,
    `username` VARCHAR(50) NOT NULL ,
    PRIMARY KEY (`id`) )
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_general_ci
-- usercommentsテーブル
CREATE  TABLE IF NOT EXISTS `usercomments` (
    `id` INT NOT NULL ,
    `user_id` INT NULL ,
    `commment` TEXT NULL ,
    PRIMARY KEY (`id`) )
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_general_ci

アソシエーションの設定。user(ユーザ)がいて、それに紐付くusercomment(ユーザのコメント)

// Userモデル
class User extends AppModel {
    var $name = 'User';
    var $hasMany = array(
        'Usercomment' => array(
            'className' => 'Usercomment',
            'foreignKey' => 'user_id'            // 省略可
        ),
    );
}

実行結果

$recursive = 0 でfind

findのみの場合、User(usersテーブル)へのselectと、それに対するUsercommment (usercommentsテーブル)へのjoinが行われます。

//  コード
    $this->data = $this->User->find( 'all');
-- SQLログ
queryLog = Array
(
    [query] => SELECT `User`.`id`, `User`.`username`, `User`.`password`, `User`.`status`, `User`.`created`, `User`.`modified` FROM `users` AS `User`   WHERE 1 = 1   
    [error] => 
    [affected] => 4
    [numRows] => 4
    [took] => 1
)

queryLog = Array
(
    [query] => SELECT `Usercomment`.`id`, `Usercomment`.`user_id`, `Usercomment`.`commment`, `Usercomment`.`status`, `Usercomment`.`created`, `Usercomment`.`modified` FROM `usercomments` AS `Usercomment`   WHERE `Usercomment`.`user_id` IN (1, 2, 3, 4)   
    [error] => 
    [affected] => 0
    [numRows] => 0
    [took] => 1
)

$recursive = -1 でfind

findの前にrecursive = -1を設定すると、User(usersテーブル)へのselectのみが行われるようになります。

//  (1) [read, findByなど]
    $this->User->recursive = -1;
    $this->data = $this->User->find( 'all');
//  もしくは
// (2) [findByなど]
    $this->data = $this->User->find( 'all', array( 'recursive' = '-1'));
-- SQLログ
queryLog = Array
(
    [query] => SELECT `User`.`id`, `User`.`username`, `User`.`password`, `User`.`status`, `User`.`created`, `User`.`modified` FROM `users` AS `User`   WHERE 1 = 1   
    [error] => 
    [affected] => 4
    [numRows] => 4
    [took] => 1
)
実行SQLをログ出力させておくとわかりやすいと思います。
SQLクエリーをログに出力する

設定箇所

考え方次第ですが、代表的には以下の2つが考えられると思います。

$recursive = -1をデフォルトに

この場合、joinが必要な場合はfindを行う際に、recursive = 0などに設定をする必要があります。

// app/Model/AppModel.php
class AppModel extends Model {
    public $recursive = -1;
}

find毎に$recursive = -1設定

今回試した例です。

個人的には、2を選択しています。
SQLのログは試験中は出力しておいて、余計な呼び出しは省略していくというのは、特にフレームワークを使用する際は注視して使用すると、もっと使い勝手がよくなると思います。もちろん、本番向けは取り除いて下さい。性能劣化につながりますので。。

Model > Model Attributes > recursive
2.1 / 2.2 / 2.3 / 2.4
  • このエントリーをはてなブックマークに追加

関連記事

Cookieログイン

今回は、ログイン画面でよくみかけるクッキーログインの機能を使ってみます。 CakePHPには、Cookieコンポーネントがあります。(PHPのsetcookieメソッドのラッパー)メソッドはwr

日付・時間のバリデーション

日付や時刻に関するバリデーションは以下のルールがビルトインされています。 date 日付 time 時刻 datetime 日時 (m:「月」を数字表記 / M:「月」を英語表記)

FormヘルパーのMagicOption (マジックオプション) 

Formヘルパーでは、「フィールド名」,「テーブルカラムのデータ型」もしくはモデルの「バリデーション設定」によりフォーム要素を決定したり、自動で属性を付与する「マジックオプション」と呼ばれるものがある

(メール・URL・電話・郵便・IP) データ バリデーション

今回は、プロフィール情報に使用されるデータに絞ったバリデーションルールです。 バリデーションルール 以下の5つのバリデーションルールがコアに用意されています。 email メールアドレス

CakeEmailでメール送信(@gmail)

CakePHP 2になって追加されたクラスCakeEmailがシンプルに使えます。これを使用してメール送信を行う処理を実装してみました。 CakeEmailクラスの読み込み /app/Config

ログローテーション

CakePHP 2.xではbootstrap.php内にあらかじめアプリケーションログの設定が書かれています。2.xで日付ごとにログファイルが切り替わるよう設定してみました。 日ごとにログを切り替え

FullCalendarを使用してカレンダーアプリケーション

カレンダーアプリケーションを作成するため、カレンダー表示できるプラグインを探索して出会ったFullcalendarを試してみました。シンプルに使用できる上に、オプションがかなり豊富です。ダウンロード

ユーザ登録(仮登録・メール・本登録)

以前1.3版で投稿した「ユーザ登録」処理の2.x版を作成しました。フローは同じで以下のようにします。 1. メールアドレス・パスワードでユーザ登録 2. この時点では仮登録として、本登録用のU

hasOne アソシエーション

hasOneアソシエーションはテーブル間で1つのレコードに対して他のテーブルに紐付くレコードが1つの場合にjoinする場合に使用します。 CakePHPのドキュメントにならってUserモデルとP

no image

HttpSocketを使用してリクエスト送信

CakePHPには、Webサービスへのリクエスト送信のためのHttpSocketクラスが用意されています。 HttpSocket get HTTP GETリクエストを発行します。デモ H

Comment

@spyder1211 へ返信する コメントをキャンセル

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

    PAGE TOP ↑