フレームワークでデータをORMがらみでjoinするときのネタ。
自分の場合はLaravel。他のフレームワークでも考え方は通じるものあるかと・・
通常のjoin
select句に何も指定せずjoin句を使うとプロパティがフラットになってしまいます。これだとカラム名が競合した時に片方が消されてしまいます。
例えばorderからorderitemをjoinしようと思った時にorderの1プロパティの中にorderitemがあり、この中にorderitemの全てのプロパティがあるというのが理想的です。
ループの中で取得
親(order)の数×子供の数(orderitem)となってしまい計算量的にありえないのでNG。
hasManyなどを動的に使用
https://readouble.com/laravel/5.1/ja/eloquent-relationships.html
上記のようなリレーションを動的に組む方法がベストっぽいです。これだと親のレコードの中にプロパティとして格納されるため、通常のjoinと違ってカラムが消されたりってことはありません。
ただこの手法だとjoin自体が実行されるのは親自体(order)をループする時になり、DBへのアクセス数が親の数×子供の数となってしまいます。(これが俗にいうN+1問題と言われるものらしいです。)
通常の取得をlazy loadingというようですね。
ちなみにディフォルトでhasManyなどのjoin関係を定義しておくと、親が絡む全てのSQLで自動的に子供がついてきてしまい、非常にめんどくなりますので、動的にリレーションの関係は作るようにしましょう。
eager loading
これを解決するのがeager loadingという手法のようでクエリを発行した瞬間にDBへのアクセスも終わります。
こうすることで
- 親のプロパティの中に子供のオブジェクトを格納し、
- かつ計算量も抑える
ということができます。
えらい単純なことですが、これに行きつくまでにそこそこ時間がかかりました・・・(汗)
参考リンク
laravelじゃないですが、参考になりそう。