Skip to content

Instantly share code, notes, and snippets.

@yano3nora
Last active February 25, 2021 14:49
Show Gist options
  • Save yano3nora/61a65b2cc4b61ce727c80fb56708a93c to your computer and use it in GitHub Desktop.
Save yano3nora/61a65b2cc4b61ce727c80fb56708a93c to your computer and use it in GitHub Desktop.
[rails: Performance Improvement] Performance Improvement in Ruby on Rails. #rails

KNOWLEDGE

JavaScript

https://developers.google.com/web/tools/chrome-devtools/rendering-tools?hl=ja

Memory

Ruby 2.6 の改善を自慢したい

メモリを食う大きめのデータを取り回すと重くなる説ある。Ruby は「全てがオブジェクト」なためメモリ消費が多め、2.2 以前は GC の性能にも問題が合って顕著に遅かったみたい。

conditions = {
  # ...
}
user_ids = []

User.where(conditions).each do |user|
  #
  # - each でクエリが実行される
  #   - SQL 実行のコスト
  #   - 仮にここで to_a すると User.where(conditions).count 分の
  #     ActiveRecord インスタンス生成 => 高コスト
  # - user.id の参照により User インスタンスが都度生成され
  #   user.id を << で追加した後 user が GC で開放されない
  #
  user_ids << user.id
  #
  # user.save は User.where(conditions).count が増える毎に
  # クエリが増えてしまういわゆる N + 1 アンチパターンになる
  #
  user.processed = true
  user.save
end

#
# - pluck, update_all で User が増えても 2 回のクエリ
# - pluck なので User インスタンスが生成されない ( SQL 発行のみ )
# - update_all はモデルのコールバック/バリデーションが働かないことに注意
#
user_ids = User.where(conditions).pluck(:id)
User.where(id: user_ids).update_all(processed: true)

TOOLS

Rails.cache

Ruby Modules, And Gems

Rails高速化のためのパフォーマンスチューニングに役立つツール 8個+α

Rails

Detection Eager Load

Rails: ActiveRecord関連付けのpreload/eager-loadをテストする2つの方法(翻訳)

さくっと確認するなら binding.pry で止めて ActiveRecord::Associations::CollectionProxy#loaded? で確認。

articles = Article.sample 3
articles.first.association(:author).loaded?  # false

ログなんかで全体的に確認したいなら ActiveSupport::Notifications#subscribed の第三引数にクエリ実行可能性のあるブロックを渡すような作りにするとよい。

require 'rails_helper'

RSpec.describe Order, type: :model do
  specify "#average_line_gross_price_today eager loading" do
    o = Order.new()
    o.order_lines.build
    o.order_lines.build
    o.save!

    count = count_queries { Order.average_line_gross_price_today }
    expect(count).to eq(2)
    # 2 を期待しつつ、実際の SQL トリガ回数は count_queries 内の
    # ActiveSupport::Notifications.subscribed で購読した
    # sql.active_record イベントのカウント総数が評価されるテスト
  end

  private

  def count_queries &block
    count = 0

    counter_f = ->(name, started, finished, unique_id, payload) {
      unless %w[ CACHE SCHEMA ].include?(payload[:name])
        count += 1
      end
    }

    ActiveSupport::Notifications.subscribed(
      counter_f,
      'sql.active_record',
      &block
    )

    count
  end
end

New Relic

newrelic.com
New Relic ドキュメント - 日本代理店の非公式ドキュメント

WEB アプリケーションのパフォーマンス解析 SaaS 。Controller#action の以下のようなパフォーマンス指標を監視可能。詳細は別メモ参照。

  • レスポンスタイム ( TTFB )
  • ビューレンダリング
  • DB スロークエリ
  • Redis などのバックエンド通信

Google PageSpeed Insights

Google PageSpeed Insights

New Relic はバックエンドまでしか解析できないので ...

  • アセットの取得速度
  • Ajax など非同期処理速度
  • ファーストビュー速度
  • JavaScript 実行時間
  • ページアイドルまでの時間

... などなどフロントエンド周りまで含めたパフォーマンスは Google PageSpeed Insights でチェックし、ローカルでは Chrome DevTools の Performance などでデバッグしていくようにする。

速度検査には Lighthouse を利用しており、こちらは Chrome 拡張もあるみたい。

Refs

Sonar - GoogleChrome Extension

今、見ているWebページのW3C標準規格の表示速度が測れるChrome用機能拡張「Sonar」

https://chrome.google.com/webstore/detail/sonar/dibilcjfahbokhiodajibcajcabfjein/related

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment