SlideShare ist ein Scribd-Unternehmen logo
Datenbankoptimierung




                  Beispiele für die
               Optimierung an der
         Ruby-on-Rails-Schnittstelle


                       Karsten Meier
                     meier-online.com
Mein Background

●
    1986: SQL im Studium
●
    1996: QuarkXpress -> HTML Converter
●
    1998-2001: WebObjects, MVC, ORM
●
    2004: Erster Kontakt mit Ruby (Pleac)
●
    Seit 2005: Handylearn Projects
●
    Seit 2009: Nutzung von Rails



                                            2
Fallbeispiel Cycosmos

●
    Community
●
    Webobjects
●
    ORM
    Enterprise Objects
●
    3 Appserver,
    1 DB Server




                                    3
Reduktion der Datenbankzugriffe

●
    Bessere
    Antwortzeiten
●
    Weniger
    Datenbanklast
●
    300% höherer
    Durchsatz
●
    Höhere Stabilität
Die Schichten einer Anwendung
Fette Objekte


                          imo
           id                           call_sign   build_year
                                 grt
                    teu

    name

speech_of_sponsor               draft
                                                        machine


                    imo_certificate
     company                                    legal_country
Schattenobjekte

    ContainerVessel.
       select('id, name')
       order('name')

●
    Read-Only                 ActiveRecord::ReadOnlyRecord
●
    Nur angegebene Attribute
●
    Exception falls
    unbekannt           ActiveRecord::MissingAttributeError

●
    ID wirft keine Exception
Rosinen picken

●
    Nur eine Spalte
●
    Objekt unwichtig
●
    pluck(column)
●
    ab Rails 3.2

ContainerVessel.pluck(:name)
['Australia', 'Brisbane', 'Busan',...]
Darf das Schiff ablegen?
Outsourcing

●
    Gewicht aller Container
●
    Berechnung kann die DB durchführen
●
    Rails sieht die einzelnen Container nicht


    @vessel.containers.inject{...}

    @vessel.containers.sum('weight')
Verknüpfte Objekte

●
    Eine Reederei mit Liste ihrer Schiffe und
    Flaggenstaaten
Ablaufdiagramm
includes()

@container_vessels =
  @company.container_vessels.
     order(:name).
     includes(:legal_country)


SELECT "container_vessels".*
   FROM "container_vessels"
   WHERE "container_vessels"."company_id" = 2
   ORDER BY name

SELECT "countries".*
   FROM "countries"
   WHERE "countries"."id" IN (8, 7, 4)
includes()

●
    Jede Abfrage liefert
    einen Objekttyp
●
    Rails behält
    Kontrolle
●
    Schachtelung
    möglich
●
    Feintuning schwierig

    .includes(:legal_country => :tax_rates)
    .select('country.image????')
Was war noch mal ein Join?
Inner/Left/Outer/Right
Rails joins

     @container_vessels =
       @company.container_vessels.
        order(:name).
        joins(:legal_country)

●
    Keine flaggenlose
    Schiffe
●
    Keine Staaten
Filtern mit joins()

 ●
     Filtern anhand von verbundenen Daten
 ●
     Nur Zielobjekte werden geliefert
 ●
     Vorsicht vor Vervielfachung
@companies = Company.order(:name).
        joins(:container_vessels).
   where(["container_vessels.build_year > ?", 2009])

SELECT "companies".*
FROM "companies"
INNER JOIN "container_vessels"
  ON "container_vessels"."company_id" = "companies"."id"
WHERE (container_vessels.build_year > 2009)
ORDER BY name
Automatischer Join
               in Associationen

class Country < ActiveRecord::Base
  has_many :registering_companies,
           :through => :registered_vessels,
           :source => 'company',
           :class_name => 'Company',
           :uniq => true
...
@companies = @country.registering_companies


SELECT DISTINCT "companies".*
FROM "companies"
INNER JOIN "container_vessels"
  ON "companies"."id" = "container_vessels"."company_id"
WHERE "container_vessels"."legal_country_id" = 10
Join direkt verwenden?
Echte Datenbankjoins aus Rails
connection = Company.connection

columns = "container_vessels.id, container_vessels.name,
   container_vessels.imo, container_vessels.teu, 
   countries.name as legal_country_name"

sql = 'SELECT ' + columns + ' FROM "container_vessels" 
  JOIN "countries" 
  ON "countries"."id" = "container_vessels"."legal_country_i
  WHERE "container_vessels"."company_id" = ' + @company.id.t
  ' ORDER BY "container_vessels".name'

@vessel_data = connection.select_all(
     sql, 'ContainerVessel Overview Load')
select_all Rückgabewerte

●
    select_all: array of hashes
●
    select_rows: array of arrays

<% @vessel_data.each do |data| %>
  <tr>
    <td><%= data['name'] %></td>
    <td><%= data['imo'] %></td>
    <td><%= data['teu'] %></td>
    <td><%= data['legal_country_name'] %></td>
   ...
<% end %>
Parameter-Überprüfung

●
    SQL-Injection          Company.where(
                              'name like '%?', input)
●
    Methoden leider
    etwas versteckt        record.sanitize_sql_array(..)
●
    Ab Rails 3.2:          replace_bind_variables()
    ActiveRecord::         quote_bound_value()
    Sanitization           connection.quote_string()
●
    Bei IDs: to_i.to_str
Schreiben

Wenn es Performanceprobleme beim Schreiben
gibt, dann sind sie meistens schwerwiegend.
IDs

●
    ID-Vergabe kann
    zentraler
    Flaschenhals sein
●
    IDs schon existent?
Transaktionen

●
    gewährleisten die Konsistenz (ACID)
●
    weniger Sperren, schnelleres Schreiben
●
    Ab 2 Schreiboperationen -> nutzen!
Massenupdates

●
    Firma wird verkauft
●
    Alle Schiffen bekommen neuen Besitzer

UPDATE container_vessels
SET company_id = 7
WHERE company_id = 5


connection.update_sql(sql, "Updating vessel...")
Verbundene Updates

●
    Beispiel Denormalisierung
●
    Name des Landes soll auch im
    Schiffsdatensatz gespeichert werden
UPDATE container_vessels, country
SET container_vessels.country_name = country.name
WHERE container_vessels.legal_country_id = country.id
Keine Angst for SQL




"Many people treat the relational database
like a crazy aunt who's shut up in an attic
and whom nobody wants to talk about"

Martin Fowler: OrmHate
... end
                                                Website von Karsten Meier:




                                             meier-online.com
Bilder:
Container ship by jogdragoon, openclipart.org
Hammer5 by Krystof Jetmar, openclipart.org
OOCL Montreal & Cosco Hope fotografiert von Karsten Meier im Hamburger Hafen 2012

Weitere ähnliche Inhalte

PDF
Storytelling For The Web: Integrate Storytelling in your Design Process
PDF
Artificial Intelligence, Data and Competition – SCHREPEL – June 2024 OECD dis...
PDF
How to Leverage AI to Boost Employee Wellness - Lydia Di Francesco - SocialHR...
PDF
2024 Trend Updates: What Really Works In SEO & Content Marketing
PDF
Risiko, Sicherheit und menschliche Entscheidungsfindungen
PDF
Rails database optimization
PDF
2024 State of Marketing Report – by Hubspot
PDF
Everything You Need To Know About ChatGPT
Storytelling For The Web: Integrate Storytelling in your Design Process
Artificial Intelligence, Data and Competition – SCHREPEL – June 2024 OECD dis...
How to Leverage AI to Boost Employee Wellness - Lydia Di Francesco - SocialHR...
2024 Trend Updates: What Really Works In SEO & Content Marketing
Risiko, Sicherheit und menschliche Entscheidungsfindungen
Rails database optimization
2024 State of Marketing Report – by Hubspot
Everything You Need To Know About ChatGPT
Anzeige

Datenbankoptimierung für Ruby on Rails

  • 1. Datenbankoptimierung Beispiele für die Optimierung an der Ruby-on-Rails-Schnittstelle Karsten Meier meier-online.com
  • 2. Mein Background ● 1986: SQL im Studium ● 1996: QuarkXpress -> HTML Converter ● 1998-2001: WebObjects, MVC, ORM ● 2004: Erster Kontakt mit Ruby (Pleac) ● Seit 2005: Handylearn Projects ● Seit 2009: Nutzung von Rails 2
  • 3. Fallbeispiel Cycosmos ● Community ● Webobjects ● ORM Enterprise Objects ● 3 Appserver, 1 DB Server 3
  • 4. Reduktion der Datenbankzugriffe ● Bessere Antwortzeiten ● Weniger Datenbanklast ● 300% höherer Durchsatz ● Höhere Stabilität
  • 6. Fette Objekte imo id call_sign build_year grt teu name speech_of_sponsor draft machine imo_certificate company legal_country
  • 7. Schattenobjekte ContainerVessel. select('id, name') order('name') ● Read-Only ActiveRecord::ReadOnlyRecord ● Nur angegebene Attribute ● Exception falls unbekannt ActiveRecord::MissingAttributeError ● ID wirft keine Exception
  • 8. Rosinen picken ● Nur eine Spalte ● Objekt unwichtig ● pluck(column) ● ab Rails 3.2 ContainerVessel.pluck(:name) ['Australia', 'Brisbane', 'Busan',...]
  • 9. Darf das Schiff ablegen?
  • 10. Outsourcing ● Gewicht aller Container ● Berechnung kann die DB durchführen ● Rails sieht die einzelnen Container nicht @vessel.containers.inject{...} @vessel.containers.sum('weight')
  • 11. Verknüpfte Objekte ● Eine Reederei mit Liste ihrer Schiffe und Flaggenstaaten
  • 13. includes() @container_vessels = @company.container_vessels. order(:name). includes(:legal_country) SELECT "container_vessels".* FROM "container_vessels" WHERE "container_vessels"."company_id" = 2 ORDER BY name SELECT "countries".* FROM "countries" WHERE "countries"."id" IN (8, 7, 4)
  • 14. includes() ● Jede Abfrage liefert einen Objekttyp ● Rails behält Kontrolle ● Schachtelung möglich ● Feintuning schwierig .includes(:legal_country => :tax_rates) .select('country.image????')
  • 15. Was war noch mal ein Join?
  • 17. Rails joins @container_vessels = @company.container_vessels. order(:name). joins(:legal_country) ● Keine flaggenlose Schiffe ● Keine Staaten
  • 18. Filtern mit joins() ● Filtern anhand von verbundenen Daten ● Nur Zielobjekte werden geliefert ● Vorsicht vor Vervielfachung @companies = Company.order(:name). joins(:container_vessels). where(["container_vessels.build_year > ?", 2009]) SELECT "companies".* FROM "companies" INNER JOIN "container_vessels" ON "container_vessels"."company_id" = "companies"."id" WHERE (container_vessels.build_year > 2009) ORDER BY name
  • 19. Automatischer Join in Associationen class Country < ActiveRecord::Base has_many :registering_companies, :through => :registered_vessels, :source => 'company', :class_name => 'Company', :uniq => true ... @companies = @country.registering_companies SELECT DISTINCT "companies".* FROM "companies" INNER JOIN "container_vessels" ON "companies"."id" = "container_vessels"."company_id" WHERE "container_vessels"."legal_country_id" = 10
  • 21. Echte Datenbankjoins aus Rails connection = Company.connection columns = "container_vessels.id, container_vessels.name, container_vessels.imo, container_vessels.teu, countries.name as legal_country_name" sql = 'SELECT ' + columns + ' FROM "container_vessels" JOIN "countries" ON "countries"."id" = "container_vessels"."legal_country_i WHERE "container_vessels"."company_id" = ' + @company.id.t ' ORDER BY "container_vessels".name' @vessel_data = connection.select_all( sql, 'ContainerVessel Overview Load')
  • 22. select_all Rückgabewerte ● select_all: array of hashes ● select_rows: array of arrays <% @vessel_data.each do |data| %> <tr> <td><%= data['name'] %></td> <td><%= data['imo'] %></td> <td><%= data['teu'] %></td> <td><%= data['legal_country_name'] %></td> ... <% end %>
  • 23. Parameter-Überprüfung ● SQL-Injection Company.where( 'name like '%?', input) ● Methoden leider etwas versteckt record.sanitize_sql_array(..) ● Ab Rails 3.2: replace_bind_variables() ActiveRecord:: quote_bound_value() Sanitization connection.quote_string() ● Bei IDs: to_i.to_str
  • 24. Schreiben Wenn es Performanceprobleme beim Schreiben gibt, dann sind sie meistens schwerwiegend.
  • 25. IDs ● ID-Vergabe kann zentraler Flaschenhals sein ● IDs schon existent?
  • 26. Transaktionen ● gewährleisten die Konsistenz (ACID) ● weniger Sperren, schnelleres Schreiben ● Ab 2 Schreiboperationen -> nutzen!
  • 27. Massenupdates ● Firma wird verkauft ● Alle Schiffen bekommen neuen Besitzer UPDATE container_vessels SET company_id = 7 WHERE company_id = 5 connection.update_sql(sql, "Updating vessel...")
  • 28. Verbundene Updates ● Beispiel Denormalisierung ● Name des Landes soll auch im Schiffsdatensatz gespeichert werden UPDATE container_vessels, country SET container_vessels.country_name = country.name WHERE container_vessels.legal_country_id = country.id
  • 29. Keine Angst for SQL "Many people treat the relational database like a crazy aunt who's shut up in an attic and whom nobody wants to talk about" Martin Fowler: OrmHate
  • 30. ... end Website von Karsten Meier: meier-online.com Bilder: Container ship by jogdragoon, openclipart.org Hammer5 by Krystof Jetmar, openclipart.org OOCL Montreal & Cosco Hope fotografiert von Karsten Meier im Hamburger Hafen 2012