Keith and Mario’s Guide to Fast Websites
From RubyConf Au 2013
Host:xinminlabs.com
Referer:https://xinminlabs.com
Cookie:rack.session=BAh7EUkiD3Nlc3Npb25faWQGOgZFVEkiRTJjMjI3NjEzYzQ3
MTZlMmYzZDky%0AMTEzOThkZDdmZjIyYjNiODBlYWI3ZmExYzU1MjRhZjYwN2FhMTBiM
GUwM2YG%0AOwBGSSIJY3NyZgY7AEZJIiUxYzlhMzhlZDBlM2VhNGJhNmFlZDM1MzFjYj
Ri%0AZWYxOQY7AEZJIg10cmFja2luZwY7AEZ7B0kiFEhUVFBfVVNFUl9BR0VOVAY7%0A
AFRJIi1mY2M3ZjA2OGU5N2Q5NzA2YTgwMDdmOTg3MjEwMjJjOThiMjdlYTIw%0ABjsAR
kkiGUhUVFBfQUNDRVBUX0xBTkdVQUdFBjsAVEkiLWRiY2MyMTZiMTBj%0AM2I1MmJkNT
g3ZTBjODIwNTZiMmIyYmE5YjJkNDYGOwBGSSIRYWNjZXNzX3Rv%0Aa2VuBjsAVEkidTA
wRDI4MDAwMDAwZnJFUSFBUU1BUUgxcV9MY2JRbG0yRXh5%0Ad3pqdm1PVjNMZGhNQS5D
SF8xaV94ZDM0X1c5czAwTDgzaHhJV0RaQTBWNW82%0AUFR1clE5cTdUWUtJOTZmUVBoS
2NfUjE3eklsQXp3NHcGOwBUSSIKZW1haWwG%0AOwBUSSIcZmx5ZXJoem0rcHJvZEBnbW
FpbC5jb20GOwBUSSILaWRfdXJsBjsA%0AVEkiSmh0dHBzOi8vbG9naW4uc2FsZXNmb3J
jZS5jb20vaWQvMDBEMjgwMDAw%0AMDBmckVRRUFZLzAwNTI4MDAwMDAxZHlrNkFBQQY7
AFRJIhFpbnN0YW5jZV91%0AcmwGOwBUSSIjaHR0cHM6Ly9saXRhLm15LnNhbGVzZm9yY
2UuY29tBjsAVEki%0ADXVzZXJuYW1lBjsAVEkiHGZseWVyaHptK3Byb2RAZ21haWwuY2
9tBjsAVEki%0ADmlzc3VlZF9hdAY7AFRJIhIxNDU0ODE2NTUxNzE3BjsAVEkiEWRpc3B
sYXlf%0AbmFtZQY7AFRJIhJSaWNoYXJkIEh1YW5nBjsAVEkiEnJlZnJlc2hfdG9rZW4G
%0AOwBUSSJcNUFlcDg2MVRTRVN2V2V1Z193R21UcEcucUlfdDNhbTBpd1JndjFr%0AVD
gyRV8yYjRiQTBMeXFWMzFoVU9Odk1SSEJGMk15V0hzbnZtb2RMVFRYVndr%0AU01UBjs
AVEkiF29yaWdpbmFsX2lzc3VlZF9hdAY7AEZAGw%3D%3D%0A--0e51b9ebf15a845e1f
17b20c0cc947cf8d9b7f60
Host:assets.xinminlabs.com
Referer:https://xinminlabs.com
require 'test_helper'
require 'rails/performance_test_help'
class HomepageTest < ActionDispatch::PerformanceTest
# Refer to the documentation for all available options
# self.profile_options = { runs: 5,
# metrics: [:wall_time, :memory],
# output: 'tmp/performance',
# formats: [:flat] }
test "homepage" do
get '/'
end
end
BrowsingTest#test_homepage (58 ms warmup)
process_time: 63 ms
memory: 832.13 KB
objects: 7,882
# controller
@comments = Comment.limit(10)
# view
<% @comments.each do |comment| %>
<%= comment.user.username %> Said: <%= comment.body %>
<% end %>
Newrelic response time is 12.3ms
# controller
@comments = Comment.includes(:user).limit(10)
# view
<% @comments.each do |comment| %>
<%= comment.user.username %> Said: <%= comment.body %>
<% end %>
Newrelic response time is 6.81ms
12.3ms vs 6.81ms | -45% |
3.88ms vs 0.621ms | -84% |
# controller
@posts = Post.limit(10)
# view
<% @posts.each do |post| %>
<%= post.title %> has <%= post.comment.size %> comments.
<% end %>
Newrelic response time is 12.3ms
# migration
add_column :posts, :comments_count, :integer
Post.all.each do |post|
Post.reset_counters(post.id, :comments)
end
# model
class Comment < ActiveRecord::Base
belongs_to :post, counter_cache: true
end
Newrelic response time is 7.04ms
12.3ms vs 7.04ms | -43% |
6.434ms vs 0.511ms | -92% |
# model
class Comment
belongs_to :post
scope :approved, -> { where(approved: true) }
end
class Post
has_many :comments
def average_rating
comments.approved.average(:rating)
end
end
# controller
@posts = Post.limit(10)
# view
<% @posts.each do |post| %>
<%= post.title %> average rating is
<%= post.average_rating %> stars
<% end %>
Newrelic response time is 17.4ms
# Gemfile
gem 'eager_group'
# model
class Post < ActiveRecord::Base
has_many :comments
define_eager_group :average_rating, :comments, :average, :rating,
-> { approved }
end
# controller
@posts = Post.eager_group(:average_rating).limit(10)
Newrelic response time is 7.48ms
17.4ms vs 7.48ms | -57% |
6.62ms vs 1.55ms | -77% |
# controller
10.times do
Post.create title: Faker::Lorem.sentence,
body: Faker::Hipster.paragraph,
user_id: rand(100) + 1
end
Newrelic response time is 35.4ms
# Gemfile
gem 'activerecord-import'
# controller
posts = []
10.times do
posts << Post.new(title: Faker::Lorem.sentence,
body: Faker::Hipster.paragraph,
user_id: rand(100) + 1)
end
Post.import posts
Newrelic response time is 11.6ms
35.4ms vs 11.6ms | -67% |
19.39ms vs 2.39ms | -88% |
Post.where("created_at < ?", 10.years.ago).update_all(archive: true)
Post.where("created_at < ?", 10.years.ago).destroy_all
Post.where("created_at < ?", 10.years.ago).delete_all
# controller
@posts = Post.limit(10)
# view
<% @posts.each do |post| %>
<%= post.title %>
<% end %>
Newrelic response time is 4.86ms
# controller
@posts = Post.select('title').limit(10)
Newrelic response time is 4.54ms
4.86ms vs 4.54ms | -7% |
0.563ms vs 0.421ms | -25% |
# controller
@posts = Post.limit(10)
# view
<% @posts.each do |post| %>
<%= post.user.username %> said <%= post.title %>
<% end %>
Newrelic response time is 12.2ms
# Gemfile
gem 'dalli'
# config/application.rb
config.cache_store = :mem_cache_store
# view
<% @posts.each do |post| %>
<% cache post do %>
<%= post.user.username %> said <%= post.title %>
<% end %>
<% end %>
Newrelic response time is 9.97ms
12.2ms vs 9.97ms | -18% |
8.11ms vs 5.79ms | -29% |
Rails.cache.read_multi
https://github.com/n8/multi_fetch_fragments
https://github.com/hooopo/second_level_cache
# controller
@posts = Post.order('created_at desc').limit(10)
# view
<% @posts.each do |post| %>
<%= post.title %>
<% end %>
SELECT "posts".* FROM "posts" ORDER BY created_at desc LIMIT 10
Newrelic response time is 21.5ms
# migration
def change
add_index :posts, :created_at
end
Newrelic response time is 4.95ms
21.5ms vs 4.95ms | -77% |
17.3ms vs 0.595ms | -97% |
# controller
@posts = Post.limit(10)
render json: @posts
Newrelic response time is 6.28ms
# Gemfile
gem 'oj'
gem 'oj_mimic_json'
Newrelic response time is 5.76ms
6.28ms vs 5.76ms | -8% |
3.92ms vs 3.28ms | -16% |
shave off 1,114 string objects on every request
shave off 34,299 objects on every request
Person.where("age > 21").each do |person|
person.party_all_night!
end
Person.where("age > 21").find_each do |person|
person.party_all_night!
end