LoginSignup
2
6

More than 5 years have passed since last update.

CakePHPとRailsの遅延ロードの定義は違う件

Last updated at Posted at 2016-06-10

CakePHPの場合

  • CakePHP2.0からモデルに追加された機能
  • モデルの初期化時ではなく、find操作が発生する時にアソシエーション先を読み込むSQLが実行される仕組み

Railsの場合

  • ActiveRecordのデフォルトの機能
  • findした時点ではアソシエーション先は読み込まれず、アソシエーション先の値が必要になった場合に初めてSQLが実行される

両者の違い

CakePHPはfindした時点でアソシエーション先が読み込まれる

  • CakePHPでは、デフォルトではfindした時点で1次アソシエーション先を全て読み込むSQLを発行する。そのため、めっちゃbelongs_toしてるモデル多いとかだと処理時間が半端なくかかる
  • そのため、CakePHPのfindにはrecursiveというプロパティがあり、これに-1を指定するとカレントテーブルのみ取得される

Railsはfindした時点では読み込まれず、値が必要になった時に読み込まれる

  • デフォルトがCakePHPのrecursive:-1の状態になっており、カレントテーブルのみ読み込まれる
  • とてもスマートだと思うが、逆にn+1問題という別の問題が発生する場合がある

N+1問題 / Eager Loading とは - Rails Webook http://ruby-rails.hatenadiary.com/entry/20141108/1415418367
N+1問題は1+N問題 - Qiita http://qiita.com/hisonl/items/763b9d6d4e90b1606635

  • 例えば、prefecture(県)とshop(店)という1:多の関係があったとして、View側でshop.prefecture.nameというように県名を取得しようとすると、県とのアソシエーションを取得するためのSQL文が店舗数だけ発行される
  • 店舗数が100件だったら、最初の全件取得のSQLと合わせて101件(n+1)
  • これを解決するにはEager Loadingという仕組みがあり、@post = Post.all.includes(:user)のようにすると、必要なアソシエーション先を指定して先に読み込むことが出来る
  • つまり、CakePHPのrecursiveの動作をRailsは明示的に指定して初めて行うということですね。しかもモデル名をシンボルで指定できるとか、さすがRailsはイケてる。
  • ちなみにRailsの場合、whereメソッドを使うとこれは条件をActiveRecord::Relationオブジェクトを返すだけで、値が必要になった時にSQLが実行されることも遅延ロードと呼ぶらしい?(うろ覚え)

さいごに

  • CakePHPはデータが全て配列だから、Viewでアソシエーション先のオブジェクトを取得するとか気のきいたこと出来んのです。全て最初にやっておかないといけない子。
  • 最初にn+1問題を聞いた時、CakePHPならループの前に<?php $prefectureName = $shops[0]['prefecture'];みたいに書けば解決するかなと考えてしまった。自然に配列脳になってしまってますね。Rails側のコードもたまに読むようにすると、非常に勉強になると思った。
2
6
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
6