SlideShare una empresa de Scribd logo
1 de 26
Descargar para leer sin conexión
work.rowanhick.com




How to avoid hanging
 yourself with Rails
  Using ActiveRecord right the first time




                                           1
Discussion 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 tomorrow

                                          2
About 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 company




                                                       3
Disclaimer
•   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



                                                        4
ActiveRecord 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.name
    end



✴Congratulations, you just overloaded your DB
    with (total number of Orders x 2) unnecessary
    SQL calls



                                                    5
What 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”




                                             6
Systemic Problem in
 Web development
I’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>”


                                        7
Atypical 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.log
                                                  8
Faker to the rescue
•   in lib/xchain.rake
    namespace :xchain do
        desc quot;Load fake customersquot;
        task :load_customers => :environment do
          require 'Faker'
          Customer.find(:all, :conditions => quot;email LIKE('%XCHAIN_
    %')quot;).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 = quot;XCHAIN_quot;+Faker::Internet.email
            c.save
          end
        end

    $ rake xchain:load_customers




                                                                     9
Eager loading
• By using :include in .finds you create sql joins
• Pull all required records in one query
  find(:all, :include => [ :customer, :order_lines ])

   ✓   order.customer, order.order_lines

  find(:all, :include => [ { :customer
  => :country }, :order_lines ])

   ✓   order.customer order.customer.country
       order.order_lines




                                                        10
Improvement
• Let’s start optimising ...
  @orders = Order.find(:all, :include => {:customers => :country} )



• Resulting SQL ...
  “SELECT orders.*, countries.* FROM orders LEFT JOIN
  customers ON ( customers.id = orders.customers_id )
  LEFT JOIN countries ON ( countries.id =
  customers.country_id)

✓ 7.70 req/s     1.4x faster



                                                                      11
Select only what you
           need
• Using the :select parameter in the find
  options, you can limit the columns you are
  requesting back from the database
• No point grabbing all columns, if you only
  want :id and :name
  Orders.find(:all, :select => ‘orders.id,
  orders.name’)




                                               12
The last slide was very
      important
• Not using selects is *okay* provided you
  have very small columns, and never any
  binary, or large text data
• You can suddenly saturate your DB
  connection.
• Imagine our Orders table had an Invoice
  column on it storing a pdf of the invoice...


                                                 13
Oops
• Can’t show a benchmark
• :select and :include don’t work together !,
  reverts back to selecting all columns
• Core team for a long time have not
  included patches to make it work
• One little sentence in ActiveRecord rdoc
  “Because eager loading generates the SELECT
  statement too, the :select option is ignored.”

                                                   14
‘mrj’ to the rescue

• http://dev.rubyonrails.org/attachment/ticket/
  7147/init.5.rb
• Monkey patch to fix select/include problem
• Produces much more efficient SQL


                                                  15
Updated finder

• Now :select and :include playing nice:
    @orders = Order.find(:all,
    :select => 'orders.id, orders.created_at, customers.name,
  countries.name, order_statuses.name',
    :include => [{:customer[:name]
  => :country[:name]}, :order_status[:name]],
    :conditions => conditions,
    :order => 'order_statuses.sort_order ASC,order_statuses.id ASC,
  orders.id DESC')



✓15.15 req/s 2.88x faster

                                                                      16
r8672 change
•   http://blog.codefront.net/2008/01/30/living-on-the-
    edge-of-rails-5-better-eager-loading-and-more/

•   The following uses new improved association load
    (12 req/s)
    @orders = Order.find(:all, :include => [{:customer
    => :country}, :order_status] )


•   The following does not
    @orders = Order.find(:all, :include => [{:customer
    => :country}, :order_status], :order =>
    ‘order_statuses.sort_order’ )


                                                          17
r8672 output...

• Here’s the SQL
  Order Load (0.000837)   SELECT * FROM `orders` WHERE (order_status_id <
  100) LIMIT 10

  Customer Load (0.000439)   SELECT * FROM `customers` WHERE
  (customers.id IN (2106,2018,1920,2025,2394,2075,2334,2159,1983,2017))

  Country Load (0.000324)   SELECT * FROM `countries` WHERE (countries.id
  IN (33,17,56,150,194,90,91,113,80,54))

  OrderStatus Load (0.000291)   SELECT * FROM `order_statuses` WHERE
  (order_statuses.id IN (10))




                                                                            18
But I want more

• Okay, this still isn’t blazing fast. I’m building
   the next killr web2.0 app
• Forgetabout associations, just load it via
   SQL, depending on application, makes a
   huge difference
• Concentrate on commonly used pages

                                                      19
Catch 22
• Hard coding SQL is the fastest solution
• No construction of SQL, no generation of
  ActiveRecord associated classes
• If your DB changes, you have to update
  SQL

‣ Keep SQL with models where possible

                                             20
It ain’t pretty.. but it’s
            fast
• Find by SQL
   class order
     def self.find_current_orders
       find_by_sql(quot;SELECT orders.id, orders.created_at, customers.name
  as customer_name, countries.name as country_name, order_statuses.name
  as status_name FROM orders LEFT OUTER JOIN `customers` ON
  `customers`.id = `orders`.customer_id LEFT OUTER JOIN `countries` ON
  `countries`.id = `customers`.country_id LEFT OUTER JOIN
  `order_statuses` ON `order_statuses`.id = `orders`.order_status_id
  WHERE order_status_id < 100 ORDER BY order_statuses.sort_order
  ASC,order_statuses.id ASC, orders.id DESCquot;)
     end
  end



• 28.90 req/s ( 5.49x faster )
                                                                          21
And the results
      find(:all)          5.26 req/s

find(:all, :include)      7.70 req/s    1.4x

find(:all, :select, :in
                         15.15 req/s   2.88x
      clude)

  find_by_sql()           28.90 req/s   5.49x



                                               22
Don’t forget indexes
• 64000 orders
    OrderStatus.find(:all).each { |os| puts
    os.orders.count }


•   Avg 0.61 req/s no indexes

•   EXPLAIN your SQL
    ALTER TABLE `xchain_test`.`orders` ADD INDEX
    order_status_idx(`order_status_id`);


•   Avg 23 req/s after index (37x improvment)


                                                   23
Avoid .count

• It’s damned slow
  OrderStatus.find(:all).each { |os| puts
  os.orders.count }


• Add column orders_count + update code
  OrderStatus.find(:all).each { |os| puts
  os.orders_count }


✓34 req/s vs 108 req/s       (3x faster)



                                            24
For the speed freaks

• Merb - http://merbivore.com
• 38.56 req/s - 7x performance improvement
• Nearly identical code
• Blazingly fast

                                             25
work.rowanhick.com




  The End



                     26

Más contenido relacionado

La actualidad más candente

Database Wizardry for Legacy Applications
Database Wizardry for Legacy ApplicationsDatabase Wizardry for Legacy Applications
Database Wizardry for Legacy ApplicationsGabriela Ferrara
 
MySQL Performance Schema in Action
MySQL Performance Schema in ActionMySQL Performance Schema in Action
MySQL Performance Schema in ActionSveta Smirnova
 
Making Magento flying like a rocket! (A set of valuable tips for developers)
Making Magento flying like a rocket! (A set of valuable tips for developers)Making Magento flying like a rocket! (A set of valuable tips for developers)
Making Magento flying like a rocket! (A set of valuable tips for developers)Ivan Chepurnyi
 
Performance Schema for MySQL troubleshooting
Performance Schema for MySQL troubleshootingPerformance Schema for MySQL troubleshooting
Performance Schema for MySQL troubleshootingSveta Smirnova
 
Capturing, Analyzing, and Optimizing your SQL
Capturing, Analyzing, and Optimizing your SQLCapturing, Analyzing, and Optimizing your SQL
Capturing, Analyzing, and Optimizing your SQLPadraig O'Sullivan
 
Agile Database Development with JSON
Agile Database Development with JSONAgile Database Development with JSON
Agile Database Development with JSONChris Saxon
 
Active Record Query Interface (1), Season 2
Active Record Query Interface (1), Season 2Active Record Query Interface (1), Season 2
Active Record Query Interface (1), Season 2RORLAB
 
Make your App Frontend Compatible
Make your App Frontend CompatibleMake your App Frontend Compatible
Make your App Frontend CompatibleOdoo
 
От экспериментов с инфраструктурой до внедрения в продакшен
От экспериментов с инфраструктурой до внедрения в продакшенОт экспериментов с инфраструктурой до внедрения в продакшен
От экспериментов с инфраструктурой до внедрения в продакшенDmitry Makhnev
 
Security: Odoo Code Hardening
Security: Odoo Code HardeningSecurity: Odoo Code Hardening
Security: Odoo Code HardeningOdoo
 
Using of TDD practices for Magento
Using of TDD practices for MagentoUsing of TDD practices for Magento
Using of TDD practices for MagentoIvan Chepurnyi
 
MySQL 8.0 Preview: What Is Coming?
MySQL 8.0 Preview: What Is Coming?MySQL 8.0 Preview: What Is Coming?
MySQL 8.0 Preview: What Is Coming?Gabriela Ferrara
 
PostgreSQL Portland Performance Practice Project - Database Test 2 Howto
PostgreSQL Portland Performance Practice Project - Database Test 2 HowtoPostgreSQL Portland Performance Practice Project - Database Test 2 Howto
PostgreSQL Portland Performance Practice Project - Database Test 2 HowtoMark Wong
 
Common schema my sql uc 2012
Common schema   my sql uc 2012Common schema   my sql uc 2012
Common schema my sql uc 2012Roland Bouman
 
10x Performance Improvements
10x Performance Improvements10x Performance Improvements
10x Performance ImprovementsRonald Bradford
 
Performance schema in_my_sql_5.6_pluk2013
Performance schema in_my_sql_5.6_pluk2013Performance schema in_my_sql_5.6_pluk2013
Performance schema in_my_sql_5.6_pluk2013Valeriy Kravchuk
 
5952 database systems administration (comp 1011.1)-cw1
5952   database systems administration (comp 1011.1)-cw15952   database systems administration (comp 1011.1)-cw1
5952 database systems administration (comp 1011.1)-cw1saeedkhan841514
 
SunshinePHP 2017 - Making the most out of MySQL
SunshinePHP 2017 - Making the most out of MySQLSunshinePHP 2017 - Making the most out of MySQL
SunshinePHP 2017 - Making the most out of MySQLGabriela Ferrara
 

La actualidad más candente (19)

Database Wizardry for Legacy Applications
Database Wizardry for Legacy ApplicationsDatabase Wizardry for Legacy Applications
Database Wizardry for Legacy Applications
 
MySQL Performance Schema in Action
MySQL Performance Schema in ActionMySQL Performance Schema in Action
MySQL Performance Schema in Action
 
Making Magento flying like a rocket! (A set of valuable tips for developers)
Making Magento flying like a rocket! (A set of valuable tips for developers)Making Magento flying like a rocket! (A set of valuable tips for developers)
Making Magento flying like a rocket! (A set of valuable tips for developers)
 
Performance Schema for MySQL troubleshooting
Performance Schema for MySQL troubleshootingPerformance Schema for MySQL troubleshooting
Performance Schema for MySQL troubleshooting
 
Capturing, Analyzing, and Optimizing your SQL
Capturing, Analyzing, and Optimizing your SQLCapturing, Analyzing, and Optimizing your SQL
Capturing, Analyzing, and Optimizing your SQL
 
Agile Database Development with JSON
Agile Database Development with JSONAgile Database Development with JSON
Agile Database Development with JSON
 
Active Record Query Interface (1), Season 2
Active Record Query Interface (1), Season 2Active Record Query Interface (1), Season 2
Active Record Query Interface (1), Season 2
 
Make your App Frontend Compatible
Make your App Frontend CompatibleMake your App Frontend Compatible
Make your App Frontend Compatible
 
От экспериментов с инфраструктурой до внедрения в продакшен
От экспериментов с инфраструктурой до внедрения в продакшенОт экспериментов с инфраструктурой до внедрения в продакшен
От экспериментов с инфраструктурой до внедрения в продакшен
 
Security: Odoo Code Hardening
Security: Odoo Code HardeningSecurity: Odoo Code Hardening
Security: Odoo Code Hardening
 
Using of TDD practices for Magento
Using of TDD practices for MagentoUsing of TDD practices for Magento
Using of TDD practices for Magento
 
MySQL 8.0 Preview: What Is Coming?
MySQL 8.0 Preview: What Is Coming?MySQL 8.0 Preview: What Is Coming?
MySQL 8.0 Preview: What Is Coming?
 
PostgreSQL Portland Performance Practice Project - Database Test 2 Howto
PostgreSQL Portland Performance Practice Project - Database Test 2 HowtoPostgreSQL Portland Performance Practice Project - Database Test 2 Howto
PostgreSQL Portland Performance Practice Project - Database Test 2 Howto
 
Common schema my sql uc 2012
Common schema   my sql uc 2012Common schema   my sql uc 2012
Common schema my sql uc 2012
 
10x Performance Improvements
10x Performance Improvements10x Performance Improvements
10x Performance Improvements
 
SQL Tracing
SQL TracingSQL Tracing
SQL Tracing
 
Performance schema in_my_sql_5.6_pluk2013
Performance schema in_my_sql_5.6_pluk2013Performance schema in_my_sql_5.6_pluk2013
Performance schema in_my_sql_5.6_pluk2013
 
5952 database systems administration (comp 1011.1)-cw1
5952   database systems administration (comp 1011.1)-cw15952   database systems administration (comp 1011.1)-cw1
5952 database systems administration (comp 1011.1)-cw1
 
SunshinePHP 2017 - Making the most out of MySQL
SunshinePHP 2017 - Making the most out of MySQLSunshinePHP 2017 - Making the most out of MySQL
SunshinePHP 2017 - Making the most out of MySQL
 

Destacado

Destacado (20)

Inventos 2008 (Cmp)
Inventos 2008 (Cmp)Inventos 2008 (Cmp)
Inventos 2008 (Cmp)
 
Sala de aula
Sala de aulaSala de aula
Sala de aula
 
Fundamentos De Ia E Sistemas Baseados em Conhecimento
Fundamentos De Ia E Sistemas Baseados em ConhecimentoFundamentos De Ia E Sistemas Baseados em Conhecimento
Fundamentos De Ia E Sistemas Baseados em Conhecimento
 
Tomas, Pepe Y Brian Ambiente Pc13
Tomas, Pepe Y  Brian Ambiente Pc13Tomas, Pepe Y  Brian Ambiente Pc13
Tomas, Pepe Y Brian Ambiente Pc13
 
mi presentacion
mi presentacionmi presentacion
mi presentacion
 
Vlak žIvota
Vlak žIvotaVlak žIvota
Vlak žIvota
 
Um Tuga Contribuinte
Um Tuga ContribuinteUm Tuga Contribuinte
Um Tuga Contribuinte
 
Las Tres Cosas Importantes
Las Tres Cosas ImportantesLas Tres Cosas Importantes
Las Tres Cosas Importantes
 
Maximilian Kolbe
Maximilian KolbeMaximilian Kolbe
Maximilian Kolbe
 
El Cerebro Y Sus Funciones Inmunologicas
El Cerebro Y Sus Funciones InmunologicasEl Cerebro Y Sus Funciones Inmunologicas
El Cerebro Y Sus Funciones Inmunologicas
 
Internet 1
Internet 1Internet 1
Internet 1
 
JanChipchase_NokiaConnection2007_vFinal_External
JanChipchase_NokiaConnection2007_vFinal_ExternalJanChipchase_NokiaConnection2007_vFinal_External
JanChipchase_NokiaConnection2007_vFinal_External
 
Dicas de esporte
Dicas de esporteDicas de esporte
Dicas de esporte
 
Comico
ComicoComico
Comico
 
Ruth Berceruelo - Viajeros Barcelo
Ruth Berceruelo - Viajeros BarceloRuth Berceruelo - Viajeros Barcelo
Ruth Berceruelo - Viajeros Barcelo
 
Ambientes Pc 8
Ambientes Pc 8Ambientes Pc 8
Ambientes Pc 8
 
Franco Con Joel
Franco Con JoelFranco Con Joel
Franco Con Joel
 
Transforming Learning: A Local and Global Perspective
Transforming Learning: A Local and Global PerspectiveTransforming Learning: A Local and Global Perspective
Transforming Learning: A Local and Global Perspective
 
Tu Mano Me Sosiene.
Tu Mano Me Sosiene.Tu Mano Me Sosiene.
Tu Mano Me Sosiene.
 
Viajero Barcelo Quico
Viajero Barcelo QuicoViajero Barcelo Quico
Viajero Barcelo Quico
 

Similar a How to avoid hanging yourself with Rails

6 tips for improving ruby performance
6 tips for improving ruby performance6 tips for improving ruby performance
6 tips for improving ruby performanceEngine Yard
 
Reverse Engineering Malicious Javascript
Reverse Engineering Malicious JavascriptReverse Engineering Malicious Javascript
Reverse Engineering Malicious JavascriptYusuf Motiwala
 
Make Your Life Easier With Maatkit
Make Your Life Easier With MaatkitMake Your Life Easier With Maatkit
Make Your Life Easier With MaatkitMySQLConference
 
Beijing Perl Workshop 2008 Hiveminder Secret Sauce
Beijing Perl Workshop 2008 Hiveminder Secret SauceBeijing Perl Workshop 2008 Hiveminder Secret Sauce
Beijing Perl Workshop 2008 Hiveminder Secret SauceJesse Vincent
 
Streamlining Your Applications with Web Frameworks
Streamlining Your Applications with Web FrameworksStreamlining Your Applications with Web Frameworks
Streamlining Your Applications with Web Frameworksguestf7bc30
 
Sangam 19 - PLSQL still the coolest
Sangam 19 - PLSQL still the coolestSangam 19 - PLSQL still the coolest
Sangam 19 - PLSQL still the coolestConnor McDonald
 
Tweaking performance on high-load projects
Tweaking performance on high-load projectsTweaking performance on high-load projects
Tweaking performance on high-load projectsDmitriy Dumanskiy
 
Mark Minasi What’S New In Active Directory For Windows 7 Server 2008 R2
Mark Minasi   What’S New In Active Directory For Windows 7   Server 2008 R2Mark Minasi   What’S New In Active Directory For Windows 7   Server 2008 R2
Mark Minasi What’S New In Active Directory For Windows 7 Server 2008 R2Nathan Winters
 
DPC2007 PHP And Oracle (Kuassi Mensah)
DPC2007 PHP And Oracle (Kuassi Mensah)DPC2007 PHP And Oracle (Kuassi Mensah)
DPC2007 PHP And Oracle (Kuassi Mensah)dpc
 
Drupal database Mssql to MySQL migration
Drupal database Mssql to MySQL migrationDrupal database Mssql to MySQL migration
Drupal database Mssql to MySQL migrationAnton Ivanov
 
Empowering the AWS DynamoDB™ application developer with Alternator
Empowering the AWS DynamoDB™ application developer with AlternatorEmpowering the AWS DynamoDB™ application developer with Alternator
Empowering the AWS DynamoDB™ application developer with AlternatorScyllaDB
 
Scaling Twitter 12758
Scaling Twitter 12758Scaling Twitter 12758
Scaling Twitter 12758davidblum
 
Php classes in mumbai
Php classes in mumbaiPhp classes in mumbai
Php classes in mumbaiaadi Surve
 
Introduction to Active Record at MySQL Conference 2007
Introduction to Active Record at MySQL Conference 2007Introduction to Active Record at MySQL Conference 2007
Introduction to Active Record at MySQL Conference 2007Rabble .
 
Troubleshooting Strategies for CloudStack Installations by Kirk Kosinski
Troubleshooting Strategies for CloudStack Installations by Kirk Kosinski Troubleshooting Strategies for CloudStack Installations by Kirk Kosinski
Troubleshooting Strategies for CloudStack Installations by Kirk Kosinski buildacloud
 
Nevmug Lighthouse Automation7.1
Nevmug   Lighthouse   Automation7.1Nevmug   Lighthouse   Automation7.1
Nevmug Lighthouse Automation7.1csharney
 
Scaling Twitter
Scaling TwitterScaling Twitter
Scaling TwitterBlaine
 

Similar a How to avoid hanging yourself with Rails (20)

6 tips for improving ruby performance
6 tips for improving ruby performance6 tips for improving ruby performance
6 tips for improving ruby performance
 
Memcached Study
Memcached StudyMemcached Study
Memcached Study
 
Reverse Engineering Malicious Javascript
Reverse Engineering Malicious JavascriptReverse Engineering Malicious Javascript
Reverse Engineering Malicious Javascript
 
Make Your Life Easier With Maatkit
Make Your Life Easier With MaatkitMake Your Life Easier With Maatkit
Make Your Life Easier With Maatkit
 
Beijing Perl Workshop 2008 Hiveminder Secret Sauce
Beijing Perl Workshop 2008 Hiveminder Secret SauceBeijing Perl Workshop 2008 Hiveminder Secret Sauce
Beijing Perl Workshop 2008 Hiveminder Secret Sauce
 
Streamlining Your Applications with Web Frameworks
Streamlining Your Applications with Web FrameworksStreamlining Your Applications with Web Frameworks
Streamlining Your Applications with Web Frameworks
 
Sangam 19 - PLSQL still the coolest
Sangam 19 - PLSQL still the coolestSangam 19 - PLSQL still the coolest
Sangam 19 - PLSQL still the coolest
 
Tweaking performance on high-load projects
Tweaking performance on high-load projectsTweaking performance on high-load projects
Tweaking performance on high-load projects
 
Payments On Rails
Payments On RailsPayments On Rails
Payments On Rails
 
Mark Minasi What’S New In Active Directory For Windows 7 Server 2008 R2
Mark Minasi   What’S New In Active Directory For Windows 7   Server 2008 R2Mark Minasi   What’S New In Active Directory For Windows 7   Server 2008 R2
Mark Minasi What’S New In Active Directory For Windows 7 Server 2008 R2
 
DPC2007 PHP And Oracle (Kuassi Mensah)
DPC2007 PHP And Oracle (Kuassi Mensah)DPC2007 PHP And Oracle (Kuassi Mensah)
DPC2007 PHP And Oracle (Kuassi Mensah)
 
Drupal database Mssql to MySQL migration
Drupal database Mssql to MySQL migrationDrupal database Mssql to MySQL migration
Drupal database Mssql to MySQL migration
 
Empowering the AWS DynamoDB™ application developer with Alternator
Empowering the AWS DynamoDB™ application developer with AlternatorEmpowering the AWS DynamoDB™ application developer with Alternator
Empowering the AWS DynamoDB™ application developer with Alternator
 
Scaling Twitter 12758
Scaling Twitter 12758Scaling Twitter 12758
Scaling Twitter 12758
 
Php classes in mumbai
Php classes in mumbaiPhp classes in mumbai
Php classes in mumbai
 
Introduction to Active Record at MySQL Conference 2007
Introduction to Active Record at MySQL Conference 2007Introduction to Active Record at MySQL Conference 2007
Introduction to Active Record at MySQL Conference 2007
 
Troubleshooting Strategies for CloudStack Installations by Kirk Kosinski
Troubleshooting Strategies for CloudStack Installations by Kirk Kosinski Troubleshooting Strategies for CloudStack Installations by Kirk Kosinski
Troubleshooting Strategies for CloudStack Installations by Kirk Kosinski
 
Nevmug Lighthouse Automation7.1
Nevmug   Lighthouse   Automation7.1Nevmug   Lighthouse   Automation7.1
Nevmug Lighthouse Automation7.1
 
Scaling Twitter
Scaling TwitterScaling Twitter
Scaling Twitter
 
Os Wilhelm
Os WilhelmOs Wilhelm
Os Wilhelm
 

Último

[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality AssuranceInflectra
 
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxGenerative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxfnnc6jmgwh
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfpanagenda
 
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...BookNet Canada
 
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS:  6 Ways to Automate Your Data IntegrationBridging Between CAD & GIS:  6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integrationmarketing932765
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI AgeCprime
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityIES VE
 
Kuma Meshes Part I - The basics - A tutorial
Kuma Meshes Part I - The basics - A tutorialKuma Meshes Part I - The basics - A tutorial
Kuma Meshes Part I - The basics - A tutorialJoão Esperancinha
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesThousandEyes
 
Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Farhan Tariq
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Hiroshi SHIBATA
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesKari Kakkonen
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Mark Goldstein
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Strongerpanagenda
 
React Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkReact Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkPixlogix Infotech
 
A Glance At The Java Performance Toolbox
A Glance At The Java Performance ToolboxA Glance At The Java Performance Toolbox
A Glance At The Java Performance ToolboxAna-Maria Mihalceanu
 
Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...
Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...
Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...Jeffrey Haguewood
 
Landscape Catalogue 2024 Australia-1.pdf
Landscape Catalogue 2024 Australia-1.pdfLandscape Catalogue 2024 Australia-1.pdf
Landscape Catalogue 2024 Australia-1.pdfAarwolf Industries LLC
 
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesMuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesManik S Magar
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Alkin Tezuysal
 

Último (20)

[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
 
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxGenerative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
 
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
 
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS:  6 Ways to Automate Your Data IntegrationBridging Between CAD & GIS:  6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI Age
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a reality
 
Kuma Meshes Part I - The basics - A tutorial
Kuma Meshes Part I - The basics - A tutorialKuma Meshes Part I - The basics - A tutorial
Kuma Meshes Part I - The basics - A tutorial
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
 
Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examples
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
 
React Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkReact Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App Framework
 
A Glance At The Java Performance Toolbox
A Glance At The Java Performance ToolboxA Glance At The Java Performance Toolbox
A Glance At The Java Performance Toolbox
 
Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...
Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...
Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...
 
Landscape Catalogue 2024 Australia-1.pdf
Landscape Catalogue 2024 Australia-1.pdfLandscape Catalogue 2024 Australia-1.pdf
Landscape Catalogue 2024 Australia-1.pdf
 
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesMuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
 

How to avoid hanging yourself with Rails

  • 1. work.rowanhick.com How to avoid hanging yourself with Rails Using ActiveRecord right the first time 1
  • 2. Discussion 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 tomorrow 2
  • 3. About 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 company 3
  • 4. Disclaimer • 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 4
  • 5. ActiveRecord 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.name end ✴Congratulations, you just overloaded your DB with (total number of Orders x 2) unnecessary SQL calls 5
  • 6. What 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” 6
  • 7. Systemic Problem in Web development I’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>” 7
  • 8. Atypical 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.log 8
  • 9. Faker to the rescue • in lib/xchain.rake namespace :xchain do desc quot;Load fake customersquot; task :load_customers => :environment do require 'Faker' Customer.find(:all, :conditions => quot;email LIKE('%XCHAIN_ %')quot;).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 = quot;XCHAIN_quot;+Faker::Internet.email c.save end end $ rake xchain:load_customers 9
  • 10. Eager loading • By using :include in .finds you create sql joins • Pull all required records in one query find(:all, :include => [ :customer, :order_lines ]) ✓ order.customer, order.order_lines find(:all, :include => [ { :customer => :country }, :order_lines ]) ✓ order.customer order.customer.country order.order_lines 10
  • 11. Improvement • Let’s start optimising ... @orders = Order.find(:all, :include => {:customers => :country} ) • Resulting SQL ... “SELECT orders.*, countries.* FROM orders LEFT JOIN customers ON ( customers.id = orders.customers_id ) LEFT JOIN countries ON ( countries.id = customers.country_id) ✓ 7.70 req/s 1.4x faster 11
  • 12. Select only what you need • Using the :select parameter in the find options, you can limit the columns you are requesting back from the database • No point grabbing all columns, if you only want :id and :name Orders.find(:all, :select => ‘orders.id, orders.name’) 12
  • 13. The last slide was very important • Not using selects is *okay* provided you have very small columns, and never any binary, or large text data • You can suddenly saturate your DB connection. • Imagine our Orders table had an Invoice column on it storing a pdf of the invoice... 13
  • 14. Oops • Can’t show a benchmark • :select and :include don’t work together !, reverts back to selecting all columns • Core team for a long time have not included patches to make it work • One little sentence in ActiveRecord rdoc “Because eager loading generates the SELECT statement too, the :select option is ignored.” 14
  • 15. ‘mrj’ to the rescue • http://dev.rubyonrails.org/attachment/ticket/ 7147/init.5.rb • Monkey patch to fix select/include problem • Produces much more efficient SQL 15
  • 16. Updated finder • Now :select and :include playing nice: @orders = Order.find(:all, :select => 'orders.id, orders.created_at, customers.name, countries.name, order_statuses.name', :include => [{:customer[:name] => :country[:name]}, :order_status[:name]], :conditions => conditions, :order => 'order_statuses.sort_order ASC,order_statuses.id ASC, orders.id DESC') ✓15.15 req/s 2.88x faster 16
  • 17. r8672 change • http://blog.codefront.net/2008/01/30/living-on-the- edge-of-rails-5-better-eager-loading-and-more/ • The following uses new improved association load (12 req/s) @orders = Order.find(:all, :include => [{:customer => :country}, :order_status] ) • The following does not @orders = Order.find(:all, :include => [{:customer => :country}, :order_status], :order => ‘order_statuses.sort_order’ ) 17
  • 18. r8672 output... • Here’s the SQL Order Load (0.000837) SELECT * FROM `orders` WHERE (order_status_id < 100) LIMIT 10 Customer Load (0.000439) SELECT * FROM `customers` WHERE (customers.id IN (2106,2018,1920,2025,2394,2075,2334,2159,1983,2017)) Country Load (0.000324) SELECT * FROM `countries` WHERE (countries.id IN (33,17,56,150,194,90,91,113,80,54)) OrderStatus Load (0.000291) SELECT * FROM `order_statuses` WHERE (order_statuses.id IN (10)) 18
  • 19. But I want more • Okay, this still isn’t blazing fast. I’m building the next killr web2.0 app • Forgetabout associations, just load it via SQL, depending on application, makes a huge difference • Concentrate on commonly used pages 19
  • 20. Catch 22 • Hard coding SQL is the fastest solution • No construction of SQL, no generation of ActiveRecord associated classes • If your DB changes, you have to update SQL ‣ Keep SQL with models where possible 20
  • 21. It ain’t pretty.. but it’s fast • Find by SQL class order def self.find_current_orders find_by_sql(quot;SELECT orders.id, orders.created_at, customers.name as customer_name, countries.name as country_name, order_statuses.name as status_name FROM orders LEFT OUTER JOIN `customers` ON `customers`.id = `orders`.customer_id LEFT OUTER JOIN `countries` ON `countries`.id = `customers`.country_id LEFT OUTER JOIN `order_statuses` ON `order_statuses`.id = `orders`.order_status_id WHERE order_status_id < 100 ORDER BY order_statuses.sort_order ASC,order_statuses.id ASC, orders.id DESCquot;) end end • 28.90 req/s ( 5.49x faster ) 21
  • 22. And the results find(:all) 5.26 req/s find(:all, :include) 7.70 req/s 1.4x find(:all, :select, :in 15.15 req/s 2.88x clude) find_by_sql() 28.90 req/s 5.49x 22
  • 23. Don’t forget indexes • 64000 orders OrderStatus.find(:all).each { |os| puts os.orders.count } • Avg 0.61 req/s no indexes • EXPLAIN your SQL ALTER TABLE `xchain_test`.`orders` ADD INDEX order_status_idx(`order_status_id`); • Avg 23 req/s after index (37x improvment) 23
  • 24. Avoid .count • It’s damned slow OrderStatus.find(:all).each { |os| puts os.orders.count } • Add column orders_count + update code OrderStatus.find(:all).each { |os| puts os.orders_count } ✓34 req/s vs 108 req/s (3x faster) 24
  • 25. For the speed freaks • Merb - http://merbivore.com • 38.56 req/s - 7x performance improvement • Nearly identical code • Blazingly fast 25