ActiveRecord4(Rails4)のSQLをEager loadingで最適化する方法

ActiveRecord4のSQLをEager loadingで最適化する方法メモ。



ActiveRecord4(Rails4)のSQLをEager loadingで最適化する方法


リレーションで紐付いたデータをActiveRecordで取得する際、普通にループを回してしまうと、テーブルの紐付けをたどるたびにSQLが発行されてしまって非常に効率が悪い。


こういう時には、Eager Loadingを使うことで、SQLの実行回数を減らして効率化することができる。


class Post < ActiveRecord::Base
  belongs_to :author
  has_many   :comments
end

上記のPostモデルのレコード数が100の場合、


# Postのレコード数が100の時、このループは201回のSQLを実行する
Post.all.each do |post|
  puts "Post:            " + post.title
  puts "Written by:      " + post.author.name
  puts "Last comment on: " + post.comments.first.created_on
end

このループを実行すると、全部で201回のクエリが実行されてしまう。Post.allで1回、各Postのauthorで100回、各Postのcomments.firstで100回。


Eager Loadingを使うことで、SQL実行回数を201回から3回に減らすことができる。


# Eager Loadingを使うことで、Postのレコード数が100の時、このループは3回のSQLを実行する
Post.includes(:author, :comments).each do |post|
  puts "Post:            " + post.title
  puts "Written by:      " + post.author.name
  puts "Last comment on: " + post.comments.first.created_on
end

さらに細かいオプションの指定方法はRails4の公式ドキュメントを見て下さい。



ActiveRecord4(ORM)を使うことの是非について


最適化のコツを知らないままORMを使うと、上記のような非効率なSQLを実行してしまうことがあるため、「ORMは一切使うべきではない」という意見を持つ人がたまにいます。


たしかに、ORMを使ったせいでハマることもあります。しかし一方で、ORMを使うことによるコード行数の削減・効率化、バリデーション機能によるバグの減少、等の長所もかなりあります。


生のSQLを使ったとしても、クエリ最適化のコツを知らないと非効率なクエリを書いてしまう点は同じです。そもそも、どんなライブラリであれ不十分な知識で利用すると非効率になるのは同じです。


これからORMについて学ぶ皆さんには、どちらか一方が良い・悪いの二元論ではなく、長所と短所があるという前提での取捨選択をしていってほしいと個人的には思います。


ORMを毛嫌いし、不十分な知識でSQLを書いた挙げ句「文字列連結によるSQL組み立て、からのSQLインジェクション」という不毛なバグを起こす開発がこれ以上増えないことを切に願います…(^^)



参考リンク


ActiveRecord::Associations::ClassMethods


著者プロフィール
Webサイトをいくつか作っています。
著者プロフィール