Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Quick Wins

Quick Wins

Six quick and easy techniques that could significantly impact the performance of your Rails application.

Steve Richert

July 07, 2014
Tweet

More Decks by Steve Richert

Other Decks in Programming

Transcript

  1. collectiveidea.com ActiveRecord::Schema.define(version: 20140702141655) do ! create_table "messages", force: true do

    |t| t.integer "sender_id" t.integer "recipient_id" t.string "subject" t.text "body" t.boolean "read", default: false, null: false t.datetime "created_at" t.datetime "updated_at" end ! create_table "users", force: true do |t| t.string "name" t.datetime "created_at" t.datetime "updated_at" t.string "username" t.string "password_digest" end ! end
  2. collectiveidea.com class MessagesController < ApplicationController before_action :require_current_user ! def index

    @messages = current_user.received_messages.new_to_old end ! def mark_read @messages = current_user.received_messages.where(id: params[:message_ids]) ! @messages.each do |message| message.update_attribute(:read, true) end ! redirect_to messages_path end ! private ! def require_current_user unless current_user redirect_to login_path, flash: { alert: "Please log in first." } end end ! def current_user User.find_by(id: cookies[:current_user_id]) end end
  3. collectiveidea.com ActiveRecord::Schema.define(version: 20140702141655) do ! create_table "messages", force: true do

    |t| t.integer "sender_id" t.integer "recipient_id" t.string "subject" t.text "body" t.boolean "read", default: false, null: false t.datetime "created_at" t.datetime "updated_at" end ! create_table "users", force: true do |t| t.string "name" t.datetime "created_at" t.datetime "updated_at" t.string "username" t.string "password_digest" end ! end Y U NO INDEX?!
  4. collectiveidea.com require "spec_helper" ! describe "Message List Performance", type: :feature

    do let!(:user) { create(:user) } ! before do create_list(:message, 1_000, recipient: user) log_in(user) end ! it "is fast!" do measure do visit(messages_path) ! 10.times do |i| # Refresh the page twice 2.times { visit(current_path) } ! # Select the first 100 unread messages dom_messages = DOM::Message.all dom_messages.slice(i * 100, 100).each(&:select) ! # Mark the selected messages as read click_button("Mark as Read") end # Rinse, repeat end end end
  5. collectiveidea.com Listing Messages 0 ms 200 ms 400 ms 600

    ms 800 ms 1,000 ms 1,200 ms 1,400 ms master database-indexes 955.4 937.2 280.5 279.8 Active Record Views
  6. collectiveidea.com Marking Messages 0 ms 10 ms 20 ms 30

    ms 40 ms 50 ms 60 ms 70 ms master database-indexes 64.0 58.7 Active Record
  7. collectiveidea.com class MessagesController < ApplicationController before_action :require_current_user ! def index

    @messages = current_user.received_messages.new_to_old end ! def mark_read @messages = current_user.received_messages.where(id: params[:message_ids]) ! @messages.each do |message| message.update_attribute(:read, true) end ! redirect_to messages_path end ! private ! def require_current_user unless current_user redirect_to login_path, flash: { alert: "Please log in first." } end end ! def current_user User.find_by(id: cookies[:current_user_id]) end end
  8. collectiveidea.com Listing Messages 0 ms 200 ms 400 ms 600

    ms 800 ms 1,000 ms 1,200 ms 1,400 ms master memoization 923.1 937.2 273.1 279.8 Active Record Views
  9. collectiveidea.com Marking Messages 0 ms 10 ms 20 ms 30

    ms 40 ms 50 ms 60 ms 70 ms master memoization 58.3 58.7 Active Record
  10. collectiveidea.com <% @messages.each do |message| %> <tr class="<%= message.read? ?

    "read" : "unread" %> message"> <td class=“action"> <%= check_box_tag("message_ids[]", message.id) unless message.read? %> </td> <td class="from"><%= message.sender.name %></td> <td class="to"><%= message.recipient.name %></td> <td class="subject"><%= message.subject %></td> </tr> <% end %>
  11. collectiveidea.com class MessagesController < ApplicationController before_action :require_current_user ! def index

    @messages = current_user.received_messages.new_to_old end ! def mark_read @messages = current_user.received_messages.where(id: params[:message_ids]) ! @messages.each do |message| message.update_attribute(:read, true) end ! redirect_to messages_path end ! private ! def require_current_user unless current_user redirect_to login_path, flash: { alert: "Please log in first." } end end ! def current_user User.find_by(id: cookies[:current_user_id]) end end
  12. collectiveidea.com Listing Messages 0 ms 200 ms 400 ms 600

    ms 800 ms 1,000 ms 1,200 ms 1,400 ms master eager-loading 631.6 937.2 153.3 279.8 Active Record Views
  13. collectiveidea.com <% @messages.each do |message| %> <tr class="<%= message.read? ?

    "read" : "unread" %> message"> <td class=“action"> <%= check_box_tag("message_ids[]", message.id) unless message.read? %> </td> <td class="from"><%= message.sender.name %></td> <td class="to"><%= message.recipient.name %></td> <td class="subject"><%= message.subject %></td> </tr> <% end %>
  14. collectiveidea.com class User < ActiveRecord::Base has_many :sent_messages, class_name: "Message", foreign_key:

    "sender_id" ! has_many :received_messages, class_name: "Message", foreign_key: "recipient_id" end
  15. collectiveidea.com class User < ActiveRecord::Base has_many :sent_messages, class_name: "Message", foreign_key:

    "sender_id" ! has_many :received_messages, class_name: "Message", foreign_key: "recipient_id", inverse_of: :recipient end
  16. collectiveidea.com Listing Messages 0 ms 200 ms 400 ms 600

    ms 800 ms 1,000 ms 1,200 ms 1,400 ms master inverse-association 563.8 937.2 141.5 279.8 Active Record Views
  17. collectiveidea.com <% @messages.each do |message| %> ! <tr class="<%= message.read?

    ? "read" : "unread" %> message"> <td class=“action"> <%= check_box_tag("message_ids[]", message.id) unless message.read? %> </td> <td class="from"><%= message.sender.name %></td> <td class="to"><%= message.recipient.name %></td> <td class="subject"><%= message.subject %></td> </tr> ! <% end %>
  18. collectiveidea.com <% @messages.each do |message| %> <% cache message do

    %> <tr class="<%= message.read? ? "read" : "unread" %> message"> <td class=“action"> <%= check_box_tag("message_ids[]", message.id) unless message.read? %> </td> <td class="from"><%= message.sender.name %></td> <td class="to"><%= message.recipient.name %></td> <td class="subject"><%= message.subject %></td> </tr> <% end %> <% end %>
  19. collectiveidea.com Listing Messages 0 ms 200 ms 400 ms 600

    ms 800 ms 1,000 ms 1,200 ms 1,400 ms master fragment-caching 592.1 937.2 32.6 279.8 Active Record Views
  20. collectiveidea.com class MessagesController < ApplicationController before_action :require_current_user ! def index

    @messages = current_user.received_messages.new_to_old end ! def mark_read @messages = current_user.received_messages.where(id: params[:message_ids]) ! @messages.each do |message| message.update_attribute(:read, true) end ! redirect_to messages_path end ! private ! def require_current_user unless current_user redirect_to login_path, flash: { alert: "Please log in first." } end end ! def current_user User.find_by(id: cookies[:current_user_id]) end end
  21. collectiveidea.com Marking Messages 0 ms 10 ms 20 ms 30

    ms 40 ms 50 ms 60 ms 70 ms master bulk-update 4.5 58.7 Active Record
  22. collectiveidea.com Listing Messages 0 ms 200 ms 400 ms 600

    ms 800 ms 1,000 ms 1,200 ms 1,400 ms master fast 483.2 937.2 13.0 279.8 Active Record Views
  23. collectiveidea.com Marking Messages 0 ms 10 ms 20 ms 30

    ms 40 ms 50 ms 60 ms 70 ms master fast 5.9 58.7 Active Record