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'            // 省略可
        ),
    );
}

実行SQLをログ出力

まず、わかりやすくするためSQLコマンドをCakeログに出力しましょう。(別でSQLログを参照できる場合はそれを確認していただければいいと思いますが、アプリケーションログに出力することで時系列としてわかりやすくなるので個人的にはこちらを採用しています。)
function logQueryに以下を追加。ここを参照にさせていただきました。

// cake/libs/model/datasources/dbo_source.php
    $logMessage = 'queryLog = '.print_r( $this->_queriesLog[count( $this->_queriesLog) - 1], true);
    if ($this->error) {
      $this->log( $logMessage, LOG_ERROR);
    } else {
      $this->log( $logMessage, LOG_DEBUG);
    }

$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のみが行われるようになります。

//  コード
    $this->User->recursive = -1;
    $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
)

設定箇所

考え方次第ですが、代表的には以下の2つが考えられると思います。
1) app/Model/AppModel.phpに設定して、デフォルトを$recursive = -1にする。
この場合、joinが必要な場合はfindを行う際に、$this->[Model]->recursive = 0;などを追加します。

class AppModel extends Model {
    public $recursive = -1;
}

2) 各々のfind処理の前に$recursive = -1を毎度設定する。今回試した例です。

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

  • このエントリーをはてなブックマークに追加

関連記事

メール送信(qdmail)

CakePHP(+qdmail)でメール送信する処理を実装しました。 準備 2つのライブラリ(.php)をダウンロードし、以下のように配置して下さい。 app/controllers/compo

no image

Sessionコンポーネント

ソース: /cake/libs/controller/components/session.php read read($name = null) セッションの情報を読み込みます。 $

no image

Debugkitをインストール

CakePHPのデバッグツールとしてはデファクトスタンダードといってもいいDebugkitをインストールしました。 ダウンロード CakePHP 1.3用 https://github.com

コントローラ内でバリデーション処理を呼び出す

通常、saveメソッドの際にバリデーション処理も自動で行われますが、save処理と切り離してバリデーションを行うこともできます。このときは、save時と若干異なる処理体系になります。 バリデーシ

no image

validateErrors と validationErrors

CakePHP試験中に気付いたことがあって、メモです。 $this->validateErrors自身バリデーション処理している 今まで、save時にバリデーションエラーメッセージををログに出力し

no image

独自のバリデーションルール

CakePHPで組み込みバリデーションをつくる方法は色々あります。 参考:Data Validation — CakePHP Cookbook v1.3 documentation 上記リンク内に

複数データベースの追加と切替

CakePHPで複数のデータベースに切替を行うということがあると思います。(個人的にはあまりない) 今回、CakePHPからWordpressのデータベースへの接続を行う機会があったので設定を試して

no image

Htmlヘルパー

ソース:\cake\libs\view\helpers\html.php charset / 文書の文字コードを設定する <?php echo $this->Html-

no image

WYSIWYGエディタを実装

WYSIWYGエディタをCakePHPにいくつか試してみました。 CKEditor 実装 // head // View(~.ctp) 解凍してwebroot/jsフ

ログインに追加の条件を付与する「userScope」

「ユーザ登録」の続きです。 ユーザ登録後、activate(statusを0に設定するを)せずに「仮登録」のままで、正しいusernameとpasswordでログインを試したところ認証に引っかかって

Message

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

*

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

    PAGE TOP ↑