0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Rails】N+1問題と対策

Posted at

#N+1問題とは
たとえば、.eachメソッド等を使って、複数(N個)のデータを取り出そうとしたとき、N回SQLが発行されてしまい、パフォーマンスの低下につながる問題。

このような、1対多のUseとMessageモデルがあったとする。

app/model/user.rb
class Message < ApplicationRecord
  has_many :messages
end
app/model/message.rb
class User < ApplicationRecord
  belongs_to :user
end

コントローラにて、ビューに渡す値を取得

app/controllers/message_controller.rb
def index
  @messages = Message.all
end

contentとそれに紐づくnameを表示

app/views/index.html.erb
<% @messages.each do |m| %>
  <span><%= m.content %> </span>
  <span><%= m.user.name %> </span>
<% end %>

その時のSQLはというと、こんな感じでレコードごとにSQLが発行されてしまいます。

Message Load (3.7ms)  SELECT `messages`.* FROM `messages` # +1の部分
  ↳ app/views/messages/index.html.erb:5
  User Load (9.4ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
  ↳ app/views/messages/index.html.erb:8
  User Load (1.0ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 3 LIMIT 1
  ↳ app/views/messages/index.html.erb:8
  CACHE User Load (0.0ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 3 LIMIT 1  [["id", 3], ["LIMIT", 1]]
  ↳ app/views/messages/index.html.erb:8
  CACHE User Load (0.0ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 3 LIMIT 1  [["id", 3], ["LIMIT", 1]]
  ↳ app/views/messages/index.html.erb:8
  ・
  ・
  ・
 (N個分続く)

#対策
gem bulletを導入する。
そうすると、こんな感じのSQLが発行され、パフォーマンスが向上します。

Message Load (1.1ms)  SELECT `messages`.* FROM `messages`
  ↳ app/views/messages/index.html.erb:5
  User Load (0.9ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` IN (1, 3, 4)
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?