Upgrade to Pro — share decks privately, control downloads, hide ads and more …

N+1と待ち時間にサヨナラ -- load_ async × strict _ loading...

Avatar for Yasuhiro Sugawara Yasuhiro Sugawara
August 21, 2025
0

N+1と待ち時間にサヨナラ -- load_ async × strict _ loading でRailsを速くする--

Avatar for Yasuhiro Sugawara

Yasuhiro Sugawara

August 21, 2025
Tweet

Transcript

  1. 並列化できるクエリが 直列で2本 実行 # app/controllers/dashboards_controller.rb def show @posts = Post.published

    # SQLは未実行 @authors = Author.where(featured: true) # SQLは未実行 end <!-- app/views/dashboards/show.html.erb --> <!-- @postsのSQLが遅延実行 --> <% @posts.each do |post|> <%= post.content %> <% end %> <!-- 上の処理が終わった後に、@authorsのSQLが遅延実行 --> <!-- 上の処理が終わる前に、@authorsのSQLを実行すれば処理全体にかかる時間を削減可能 --> <% @authors.each do |author|> <%= author.name %> <% end %> 5
  2. load_async でクエリを非同期実行して、並列化 # app/controllers/dashboards_controller.rb def show @posts = Post.published.load_async #

    SQLが非同期実行 @authors = Author.where(featured: true).load_async # SQLが非同期実行 # 結果的に、@postsと@authorsの両方のSQLが並列化 end <!-- app/views/dashboards/show.html.erb --> <!-- SQL結果が未取得なら待機し、取得済みなら以下を実行 --> <% @posts.each do |post|> <%= post.content %> <% end %> <!-- SQL結果が未取得なら待機し、取得済みなら以下を実行 --> <% @authors.each do |author|> <%= author.name %> <% end %> 6
  3. strict_loading でN+1を検出して止める class Article < ActiveRecord has_one :author end #

    irb articles = Article.all.strict_loading articles.map { it.name } => ActiveRecord::StrictLoadingViolationError articles = Article.all.includes(:author).strict_loading articles.map { it.name } => ['Alice', 'Bob'] 注意: includes なしで多発 / 全体ONは段階的に 8
  4. 適用モードの段階拡大 1. 局所オン Article.all.strict_loading 2. モデル単位 class Article < ActiveRecord

    self.strict_loading_by_default = true end 3. 全体適用 config.active_record.strict_loading_by_default = true config.active_record.action_on_strict_loading_violation = :log 9