高速化の手筈を整える
リクエストを高速化するためには、まず遅い原因を見つけることが大事!
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は幸いにもドキュメントが充実してるので比較的高速化しやすい言語かと!