24
18

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 5 years have passed since last update.

railsで効率的なクエリを作るためのtips5選

Last updated at Posted at 2018-02-04

ActiveRecordは便利だけど、どんなSQLが発行されてるかデータベースへの不要なアクセスをしていないかなどを意識してより効率的なクエリを作っていきましょう╭( ・ㅂ・)و ̑̑

selectとpluck

値が欲しいだけならpluckを使うべきだけど、メソッドも使いたい場合はselectを使ったほうが良い。

  • selectは選択したフィールドを取り出しモデルのメソッドとリレーションにアクセスできるモデルオブジェクトが返ってくる。
  • pluckは選択したフィールドを取り出し値の配列を返すのでメモリは少なくなる。

ActiveRecordのクエリメソッドよりRubyメソッドを使う

クエリメソッドの代わりにRubyメソッドを使うことが出来るなら不要なデータベース呼び出しを減らせる。
例えばcountではなくlengthを使うようにする。

eager_loadを使ってN+1クエリを防止する

includesやeage_loadを正しく使ってN+1クエリが発行されないように注意する。
詳細は下記リンクの記事を読むと理解が深まる。

# このコードではクエリが11回も発行されてる。
translators = Translator.first(10)
translators.each do |translator|
  translator.books.pluck(:title)
end

# `includes(:posts)`を使うことによってクエリを1回にして解決することが出来る。
translators = Translator.first(10).includes(:books)
translators.each do |translator|
  translator.books.pluck(:title)
end

find_eachを使う

大量のメモリを消費する場合、パフォーマンスが低下する。
そういうときはfind_eachを使ってレコードを分割取得して処理すると良い。

複数レコードの更新をまとめて行う

同じ値で複数レコードを更新する場合は下のコードで実現できる。

User.where(is_admin: true).update_all(is_admin: false)

異なる値で複数レコードを更新したい場合は単一のクエリでは不可能だしパフォーマンスが低くなる。
だけどトランザクションブロックにラップすると、すべてのレコードが一度に更新されず、同じ量のクエリが実行されてもトランザクションは1回だけのコミットになるためパフォーマンスが向上する。

# ラップされていない
20.times do |i|
  Book.update(title: "UPDATE_TITLE#{i}")
end

# トランザクションで更新をラップする
ActiveRecord::Base.transaction do 
  20.times do |i|
    Book.update(title: "UPDATE_TITLE#{i}")
  end
end
24
18
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
24
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?