1
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.

User.allを使わない。selectへ。

Posted at

本記事の目的: モデルから取り出す際に、不要なデータ量を抑える

結論

user_controller.rb(変更前
:
def index
  @users = User.all.page(params[:page])
end

def following
  @title = "フォロー"
  @user = User.find(params[:id])
  @users = @user.following.page(params[:page])
  render "show_follow"
end
:
user_controller.rb(変更後
:
def index
  @users = User.select(:id, :username).
		includes([:works, avatar_attachment: :blob]).
		page(params[:page])
end

def following
  @title = "フォロー"
  @user = User.find(params[:id])
  @users = @user.following.select(:id, :username).
		includes([:works, avatar_attachment: :blob]).page(params[:page])
  render "show_follow"
end
:

本文

例の如くN+1問題の解消に取り掛かるべく、includesを用いて関連付けされているデータを同時に取り出す事で、クエリの発行を抑えていた。

そこでもう一つ。User.allの利用をやめることにした。理由としては、モデルから取り出す不要なデータ量を抑えるためである。解決方法としては、selectメソッドを用いることで、必要なデータだけを指定することとする。

具体例を以下に示します。

User.all
=>   TRANSACTION (0.4ms)  BEGIN
  User Load (0.8ms)  SELECT `users`.* FROM `users`
[#<User id: 1, username: "Test_User", email: "test@example.com", created_at: "2021-05-03 13:07:22.877662000 +0900", updated_at: "2021-05-03 13:07:58.184592000 +0900", uid: nil, provider: nil, description: "My name is Test_User", website: "http://example.com/">,
 #<User id: 2, username: "Mon Mothma", email: "test1@example.com", created_at: "2021-05-03 13:07:23.807304000 +0900", updated_at: "2021-05-03 13:07:58.296445000 +0900", uid: nil, provider: nil, description: "My name is Savage Opress", website: "http://example.com/">,
 :
 #<User id: 22, username: "Bail Organa", email: "test21@example.com", created_at: "2021-05-03 13:07:29.297810000 +0900", updated_at: "2021-05-03 13:07:29.297810000 +0900", uid: nil, provider: nil, description: "My name is Nute Gunray", website: "http://example.com/">]
User.select(:username, :id)
=>   User Load (1.3ms)  SELECT `users`.`username`, `users`.`id` FROM `users`
[#<User username: "Test_User", id: 1>,
 #<User username: "Mon Mothma", id: 2>,
 :
 #<User username: "Bail Organa", id: 22>]

以上のように結果は歴然であるが、必要なデータだけを取り出すことに成功した。ちなみにこれは、2行目にあるActiveRecordが発行するSQLの違いにより発生している。

User.all
=>   User Load (0.8ms)  SELECT `users`.* FROM `users`

User.select(:username, :id)
=>   User Load (1.3ms)  SELECT `users`.`username`, `users`.`id` FROM `users`

また、これは関連付けを行っているモデルにおいても同様の事が可能であった。

これもActiveRecordが発行するクエリに準じている事がわかる。

  pry(main)> user = User.first
  User Load (1.9ms)  SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
=> #<User id: 1, username: "Test_User", email: "test@example.com", created_at: "2021-05-03 13:07:22.877662000 +0900", updated_at: "2021-05-03 13:07:58.184592000 +0900", uid: nil, provider: nil, description: "My name is Test_User", website: "http://example.com/">

# 変更前
  pry(main)> user.following
=>   User Load (0.9ms)  SELECT `users`.* FROM `users` INNER JOIN `relationships` ON `users`.`id` = `relationships`.`followed_id` WHERE `relationships`.`follower_id` = 1
[#<User id: 3, username: "Lyra Erso", email: "test2@example.com", created_at: "2021-05-03 13:07:24.080580000 +0900", updated_at: "2021-05-03 13:07:58.435753000 +0900", uid: nil, provider: nil, description: "My name is Jango Fett", website: "http://example.com/">,
 #<User id: 4, username: "Borvo the Hutt", email: "test3@example.com", created_at: "2021-05-03 13:07:24.351829000 +0900", updated_at: "2021-05-03 13:07:58.993427000 +0900", uid: nil, provider: nil, description: "My name is Darth Sidious", website: "http://example.com/">,
 :
 #<User id: 21, username: "Mon Mothma", email: "test20@example.com", created_at: "2021-05-03 13:07:29.023478000 +0900", updated_at: "2021-05-03 13:07:29.023478000 +0900", uid: nil, provider: nil, description: "My name is Jango Fett", website: "http://example.com/">]

# 変更後
  pry(main)> user.following.select(:id, :username)
=>   User Load (1.7ms)  SELECT `users`.`id`, `users`.`username` FROM `users` INNER JOIN `relationships` ON `users`.`id` = `relationships`.`followed_id` WHERE `relationships`.`follower_id` = 1
[#<User id: 3, username: "Lyra Erso">,
 #<User id: 4, username: "Borvo the Hutt">,
 :
 #<User id: 21, username: "Mon Mothma">]

以上です!

最後まで読んで頂きありがとうございました!

1
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
1
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?