質問: current_user.setting`とすると思います。 しかし同時にsettingの情報も取得したいので、 ``` @current_user ||= User.includes(:setting).references(:setting).find(user_id) ``` という風に書けば、SQL発行は1回で済むと思います。 しかし、eager_load, preload, キャッシュなどの情報があり、ベストプラクティスとしてはどのような考え方なのかがわかりません。 例えば、`current_user.setting`で取得して、`current_user`と`@user_setting`を2回のSQLで取得するのと、referencesを使ってjoinして取得するのとでは、SQLコストは同一として問題ないとして、 Rails内のメモリ管理(キャッシュ)の機構で影響がないのか?などです。 また、`current_user`ヘルパーが ``` def current_user @current_user ||= User.find(id) #idは何かしらで取得 end ``` となっていた場合、 知識がなく確信がないのですが、`||=`としておくと一度のアクセスで`current_user`は1度のSQL処理しかしないという記述がありました(Railsチュートリアル)。 しかし、`includes`と`references`を利用すると`current_user`ヘルパーで`current_user`を呼び出すたびにSQLが呼び出されているログが確認できました(ログが`User Load`ではなく`SQL (4.3ms)`となっているのはそういうことですよね?)。 `includes`, `references`を使わずに、個別に取得したほうがよいのでしょうか?
回答: 質問の内容をざっくりまとめると、DBアクセス回数を減らすことにどこまでこだわるべきか?ということだと理解しましたが、合っているのでしょうか? 僕に言わせるなら、この質問に対しては「ケースバイケースです」というあまり身のない回答になってしまいます。 もちろんDBアクセス数は減らせるなら減らすに越したことはないと思いますが、どこまで神経質にこだわるべきかはアプリケーションの性質に寄ります。 常に大量のアクセスをさばく必要があり、レスポンスが何よりも大事、というアプリケーションであれば徹底的にDBアクセスを減らすべし、という方針も出てくると思います。(そもそも、他にもチューニングポイントがたくさんありそうです) 逆にそういうアプリケーションでなければ、そこまで神経質にDBアクセスを減らす必要はないと思います。 簡単な工夫で回避できるならそれで良いと思いますが、アクセス数を減らすことにこだわるあまり、コードがトリッキーになってしまうぐらいなら、僕はコードのシンプルさを取ります。 そしてDBアクセス数がボトルネックになってきたタイミングで、なんらかのパフォーマンスチューニングを検討します。 というわけで、「ケースバイケースです」という答えになってしまうのはそういう理由からなのでした。 もし、kntmrkmさんが「まだRailsアプリを学習し始めたばかり」という段階なのであれば、コードのシンプルさを優先する、ということで良いと思います。 テーブルの一覧表示など、普通に実行するとN+1問題が発生することが明らかでなおかつ、コード的にも簡単に `join` や `includes` を組み合わせられる時だけ、そういった処理を入れるのが良いと思います。 ちなみに、N+1問題に関してはbulletというgemを導入すると、自動的に警告を上げてくれるので結構便利かもしれません。 以上ご参考までに。 ### 追伸 RailsやSQLに限らず、パフォーマンス改善全般の考え方や戦略についてはCODE COMPLETEの下巻(第25章)が役に立ちます。 これを読むと、「こういうケースはどうすべきか」という指針が自分の中で立てられるようになるかもしれません。 CODE COMPLETE 第2版 下