超わかりやすいN+1問題の解説
Category : DB

N+1問題のざっくり説明
N+1問題は、何度も同じような処理をする非効率な問題のことを指します。
この問題は画面の表示速度やデータ通信量に直結してくることもあるので、早急に対処しておきたい問題でもあります。
例え話でわかりやすく
わかりやすく例え話をしてみましょう。
ある日、上司が会議室にある書類を取ってくるようにあなたに指示したとします。書類には社員番号が記載してあり、ついでに該当の社員へ書類を配るように言われました。 このとき、普通の人であれば会議室の書類をまとめて運び出してから社員に配るでしょう。しかし、普通の人でない場合、会議室から1枚1枚取り出し社員に配るかもしれません。このような何度も同じ処理をする問題がN+1です。
コードで表現
例え話で出した書類の話をベースに、Railsのコードを用いてN+1問題を解説します。
DocumentsとEmployeesの2つのテーブルがあり、この2つは社員番号でリレーションを持っているとします。
Documents.all.each do |docs|# employeesは従業員テーブル# employee_idは社員番号employee_id = docs.employees.idp "番号#{employee_id}の社員に書類を渡しました。"end
この書き方をした場合、Documentsテーブルから全てのデータを取得した後にDocumentsの全データ数分、社員番号を取得するクエリが発行されます。
RailsではN+1問題を解消するために、何度もクエリを発行させないようにすることができます。
Documents.preload(:employees).all.each do |docs|# employeesは従業員テーブル# employee_idは社員番号employee_id = docs.employees.idp "番号#{employee_id}の社員に書類を渡しました。"end
このようにpreloadを挟むことで、associationをキャッシュしておくことができます。 つまり、今回のコードの例だとIN句に全ての社員番号が持たされるので、クエリの発行数は2回に抑えられます。
ちなみに、RailsにはN+1問題を検出してくれるbulletというgemがあります。検出結果はコンソール上に出るので、無駄なSQL発行を簡単にチェックすることができます。