SlideShare uma empresa Scribd logo
1 de 26
Baixar para ler offline
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

Mais conteúdo relacionado

Mais procurados

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
 

Mais procurados (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
 

Destaque

Destaque (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
 

Semelhante 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
 

Semelhante 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

Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessPixlogix Infotech
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 

Último (20)

Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 

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