We are unable to create an online viewer for this document. Please download the document instead.
work.rowanhick.comHow to avoid hanging yourself with RailsUsing ActiveRecord right the first time1Discussion tonight• Intended for new Rails Developers• People that think Rails is slow• Focus on simple steps to improve common :has_many performance problems• Short - 15mins• All links/references up on http://work.rowanhick.com tomorrow2About me• New Zealander (not Australian)• Product Development Mgr for a startup in Toronto• Full time with Rails for 2 years• Previously PHP/MySQL for 4 years• 6 years Prior QA/BA/PM for Enterprise CAD/CAM software dev company3Disclaimer• For sake of brevity and understanding, the SQL shown here is cut down to “psuedo sql”• This is not an exhaustive in-depth analysis, just meant as a heads up• Times were done using ApacheBench through mongrel in production mode• ab -n 1000 http://127.0.0.1/orders/test_xxxx 4ActiveRecord lets you get in trouble far to quick. • Super easy syntax comes at a cost. @orders = Order.find(:all)@orders.each do |order| puts order.customer.name puts order.customer.country.nameend✴Congratulations, you just overloaded your DB with (total number of Orders x 2) unnecessary SQL calls5What happened there?• One query to get the orders@orders = Order.find(:all)“SELECT * FROM orders” • For every item in the orders collection customer.name:“SELECT * FROM customers WHERE id = x”customer.country.name:“SELECT * FROM customers WHERE id = y”6Systemic Problem in Web developmentI’ve seen:- 15 Second page reloads - 10000 queries per page“<insert name here> language performs really poorly, we’re going to get it redeveloped in <insert new language here>”7Atypical root cause• Failure to build application with *real* data• ie “It worked fine on my machine” but the developer never loaded up 100’000 records to see what would happen• Using Rake tasks to build realistic data sets• Test, test, test• tail -f log/development.log8Faker to the rescue• in lib/xchain.rake namespace :xchain do desc "Load fake customers" task :load_customers => :environment do require 'Faker' Customer.find(:all, :conditions => "email LIKE('%XCHAIN_%')").each { |c| c.destroy } 1..300.times do c = Customer.new c.status_id = rand(3) + 1 c.country_id = rand(243) + 1 c.name = Faker::Company.name c.alternate_name = Faker::Company.name c.phone = Faker::PhoneNumber.phone_number c.email = "XCHAIN_"+Faker::Internet.email c.save end end$ rake xchain:load_customers9Eager loading• By using :include in .finds you create sql joins• Pull all required records in one queryfind(:all, :include => [ :customer, :order_lines ])✓ order.customer, order.order_linesfind(:all, :include => [ { :customer => :country }, :order_lines ])✓ order.customer order.customer.country order.order_lines10
Add New Comment