LoginSignup
1
3

More than 5 years have passed since last update.

Railsで11sかかるリクエストを0.5sにした話

Last updated at Posted at 2017-12-16

高速化の手筈を整える

リクエストを高速化するためには、まず遅い原因を見つけることが大事!

rack-mini-profilerの導入

コードの実行からレンダーまでの内訳を分析できるので、Rails高速化の分析には必須

rack-mini-profilerの恩恵

  • N + 1問題
  • 実際のSQL
  • slow query Railsで実装するとActiveRecordがSQLをよしなに組み立ててくれるため、ちょっと違和感のあるSQLが多々ある。

具体的に何が確認できるの

ここで確認できることは
- SQL の中身と時間
- レンダーにかかる時間

$ vi Gemfile


gem 'rack-mini-profiler', require: false

rack-mini-profilerの開発環境での準備

 $ bundle exec rails g rack_profiler:install

rack-mini-profilerの設定ファイル

$ vi config/initializers/rack_profiler.rb

if Rails.env == 'development'
  require 'rack-mini-profiler'

  # initialization is skipped so trigger it
  Rack::MiniProfilerRails.initialize!(Rails.application)
end

準備は整ったので分析開始

Rails serverを再起動すると画面左上にページのロードにかかった時間が表示されるようになる。

あれ、画面左上にないよ!

僕の環境の場合、htmlファイルじゃないと表示されなかったので、
実際の該当ページをリロードして、そのあと別タブで自分のサイトの404のURLを叩いて確認しました!

あれQueryが以上に多い

そ、それは、N+1 問題の可能性が大きい。
具体的に話すとeach分の中でexists?などオブジェクトの検索がかかると再度Queryが走るため要注意。

サンプルコード

articles.each do |article|
  if article.comments.exists? # ここでN+1です
    puts article.comments.author
  end
end

あとは遅いクエリーを徹底的に速くする

雑に書くと

class ArticleService
  def recommend_article_first
    article = Article.recommend_article.first
    #ここでarticleがN回呼び出される
    {
      id: article.id,     
      url: article.url,
      title: article.title,
      category_id: article.category_id,
    }
  end
end

なんでこれがだめか

文法的におかしいだろは置いといてObjectを生成してみると分かる通り、毎回違うObjectが生成されていることがわかります。

だめな例


class Onigiri
  def hello
    puts "Hello"
  end
end

puts Onigiri.new.object_id
70283626235260
=> nil
puts Onigiri.new.object_id
70283622696580
=> nil
puts Onigiri.new.object_id
70283626251680
=> nil

オブジェクトが再生成されないことがわかる

良い例


class Onigiri
  def hello
    puts "Hello"
  end
end

@onigiri = Onigiri.new
=> #<Onigiri:0x007fd85d264110>
puts @onigiri.object_id
70283626225800
=> nil
puts @onigiri.object_id
70283626225800
=> nil
puts @onigiri.object_id
70283626225800
=> nil

毎回同じObjectが使われていることがわかります。

実際の使い方

class Onigiri
  # 例1
  def hello  
    @hello ||= puts "Hello"
  end

  # 例2
  def world
    @world ||= Begin
      world= puts "World!"
    end
  end
end

最後に言いたいこと

高速化には、実際の遅い要因を把握することが大事で、それに対して必ず適切な方法があるので、頑張って見つけることが重要!
Rubyは幸いにもドキュメントが充実してるので比較的高速化しやすい言語かと!

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