ActiveRecord の Eager Loading を使うと、圧倒的にパフォーマンスが上がる

投稿日: 2021年 3月 8日

ActiveRecord の Eager loading の機能を試してみました。

例えば、下記のような レコードを取得するコードがあります。

pokemons = Pokemon.includes(:abilities, :moves, :types).all
pokemons = Pokemon.all

どちらも、ポケモンのレコードをすべて取得する点は共通です。

前者と後者の比較

前者は、includes で pokemons テーブルに関連するテーブルを指定しています。
こうすることで、Eager Loading のクエリになり、一行で、すべてのテーブルに対して検索を行います(join が実行されている?)

後者は、pokemons テーブルのみ検索を行います。このとき、まだ abilitiesmovestypes に対するレコード検索は行われません。
このコードの行の後、ActiveRecord のインターフェースを使って、紐づくレコードを各テーブルから取得することができます。

どちらも必要なレコードを取得するという点に置いては違いがありません。
しかし、後者の場合、pokemons テーブルのレコードの数の分だけ、abilitiesmovestypesへの検索を行うので、かなりコストがかかります。

前者であれば、4回のSQL実行で済みます
1. pokemons テーブルから全レコード取得
2. 1. で取得したレコードにある外部キーの値を使って abilities を検索
3. 2. と同じことを movestypes テーブルに対しても行う

所要時間の計測

この2つのやり方で検索処理の完了にかかる時間を計測してみました。
DBから取得する最終的なデータのサイズは約1.2MBです。

  • 前者: includes を用いて Eager Loading した場合 => 1~2秒
  • 後者: pokemons の1レコード毎に関連テーブルの検索を行った場合 => 10~16秒

プログラミングに関するオススメ書籍