Rails: Active Record APIクイズで最大の難問はどれか(翻訳)
RailsのActiveRecord
モジュールは、このフレームワークの成功と普及に大きく貢献したコアコンポーネントの1つです。私たちは数か月前に、ActiveRecord
APIの知識を問うクイズを公開しました。この短い記事では、このクイズの平均的な成績を確認して、どの問題が回答者にとって最も難しかったかを明らかにします。
はじめに
これまで最も人気が高かったクイズは、以下のクイズでした。
クイズは10問で、Railsエコシステムで重要な要素であるActiveRecord
に関するさまざまな方面の知識をセルフテストできます。
本記事では、全回答者から寄せられた解答を集計して、どんな回答が寄せられたか、そしてどの問題が最も難しかったかを明らかにします。
成績別の内訳
本記事執筆時点では1,779件の回答が登録されており、平均点は35%でした。1人の回答者が何度も回答している可能性もありますが、結果には影響しないでしょう。得点分布を以下の棒グラフにまとめました。
Rails ActiveRecord
APIクイズ受験者の得点分布
平均点が35%と予想外に低かったのですが、棒グラフの最頻値が40〜49になっていることがわかります。平均値が低めになったのは、高得点者が少ないために、このデータの得点分布が低い方に偏ったからです。70%超えの方は95パーセンタイルに入っています。80%超えの方は上位1.5%入りです。
問題別の内訳
次に、個別の問題についてユーザーがどう回答したかを見てみましょう。以下の棒グラフのバーをクリックすると、その問題のスクリーンショットが表示されます(訳注: 動的な操作は元記事で行ってください)。
最も難易度の高かった問題
最も難しかったのは問9で、正答率はわずか2.35%でした。この問9では、さまざまなプリロードやeager loadingの手法に関する知識が問われます。これらの手法について詳しくはBigBinaryの以下の記事で詳しく説明されています1。
参考: Preload, Eagerload, Includes and Joins - BigBinary Blog
実際の問9は以下のようなものでした。
Rails ActiveRecord
クイズの最難問
DB内のデータにかかわらず、以下の中で単一のSQL文をデータベースに発行するパターンを選べ(複数回答可)
ドメインモデルは、User
クラスとhas_many :posts
というかなりシンプルなものになっており、Post
ごとにtitle
属性があります。
User.joins
パターンUser.joins
パターンは、関連付けされたレコードによってユーザーをフィルタするのに用いられますが、このとき、関連付けされたレコードを読み込まない点に注意が必要です。その結果、関連付けられるPost
オブジェクトにアクセスしようとするたびにデータベースから読み込まなければならなくなります。これは、あの悪名高いN+1問題の原因になりがちです。User.preload
パターンUser.preload
パターンでは、User
モデルと、関連付けられるPost
モデルが両方ともメモリに読み込まれます。しかし、これは2つの異なるクエリによって実現されています。1つはUser
レコードを読み込むクエリで、もう1つはそのユーザーに関連付けられているすべてのPost
レコードを読み込むクエリです。preload
を使うと、この2段階読み込みが行われるため、関連付けられるレコードの属性でフィルタできなくなってしまいます。User.eager_load
パターンUser.eager_load
パターンでは、User
モデルと、関連付けられるPost
モデルを両方ともメモリに読み込みますが、このとき単一のLEFT OUTER JOIN
クエリを使います。つまりこれは正しい回答です。User.includes
パターンUser.includes
パターンはUser.preload
と同じことを行いますが、関連付けられているテーブル内の値でクエリをフィルタできる点が異なります。関連付けられているテーブルをwhere
句を適用する形でフィルタする場合、このincludes
メソッドはUser
とPost
のレコードを両方とも単一のLEFT OUTER JOIN
クエリで読み込みます。つまりこれも正しい回答です。
まとめ
本記事では、以前公開したRails ActiveRecord
APIクイズに登録された結果を簡単に分析してみました。最も難易度が高かった問題は、Railsで関連付けされているレコードを読み込むときのpreload
、eager_load
、joins
、includes
の違いを理解しているかどうかを問われます。
短い記事ですが、お役に立てられれば幸いです。ご質問やお気づきの点がありましたら元記事末尾のコメント欄までどうぞ。本記事をお楽しみいただけましたら、新着記事をすぐ読めるようぜひ購読をご検討ください。お読みいただきありがとうございました。
参考情報
- 元のクイズ: Test Yourself on Rails ActiveRecord API
- Preload, Eagerload, Includes and Joins - BigBinary Blog
preload
、eager_load
、joins
、includes
の違いを解説するBigBinaryの記事: preload, eager-load, join and includes
関連記事
- 訳注: k0kubunさんによる記事『ActiveRecordのjoinsとpreloadとincludesとeager_loadの違い - Qiita』もどうぞ。 ↩
概要
元サイトの許諾を得て翻訳・公開いたします。
参考: 週刊Railsウォッチ20230221: Active Record APIクイズ