SlideShare ist ein Scribd-Unternehmen logo
1 von 30
Downloaden Sie, um offline zu lesen
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

Ähnlich wie Datenbankoptimierung für Ruby on Rails

Von 0 auf 100 - Performance im Web
Von 0 auf 100 - Performance im WebVon 0 auf 100 - Performance im Web
Von 0 auf 100 - Performance im WebSebastian Springer
 
Legacy WebApps mit AngularJS pimpen
Legacy WebApps mit AngularJS pimpenLegacy WebApps mit AngularJS pimpen
Legacy WebApps mit AngularJS pimpenPhilipp Burgmer
 
Von Typo3 zu Plone - Ein Migrationsbericht
Von Typo3 zu Plone - Ein MigrationsberichtVon Typo3 zu Plone - Ein Migrationsbericht
Von Typo3 zu Plone - Ein MigrationsberichtAndreas Schiweck
 
MongoDB für Java-Programmierer
MongoDB für Java-ProgrammiererMongoDB für Java-Programmierer
MongoDB für Java-ProgrammiererUwe Printz
 
MongoDB für Java Programmierer (JUGKA, 11.12.13)
MongoDB für Java Programmierer (JUGKA, 11.12.13)MongoDB für Java Programmierer (JUGKA, 11.12.13)
MongoDB für Java Programmierer (JUGKA, 11.12.13)Uwe Printz
 
Entity Framework hinter den Kulissen
Entity Framework hinter den KulissenEntity Framework hinter den Kulissen
Entity Framework hinter den KulissenAndré Krämer
 
bccon-2014 adm01 tipps-und-skripts-aus-dem-leben-eines-ibm-connections-admins
bccon-2014 adm01 tipps-und-skripts-aus-dem-leben-eines-ibm-connections-adminsbccon-2014 adm01 tipps-und-skripts-aus-dem-leben-eines-ibm-connections-admins
bccon-2014 adm01 tipps-und-skripts-aus-dem-leben-eines-ibm-connections-adminsICS User Group
 
Tipps und Skripts aus dem Leben eines Connections Admins
Tipps und Skripts aus dem Leben eines Connections AdminsTipps und Skripts aus dem Leben eines Connections Admins
Tipps und Skripts aus dem Leben eines Connections AdminsKlaus Bild
 
Icsug conf 14_tipps-und-skripts-fuer-ibm-connections-administratoren
Icsug conf 14_tipps-und-skripts-fuer-ibm-connections-administratorenIcsug conf 14_tipps-und-skripts-fuer-ibm-connections-administratoren
Icsug conf 14_tipps-und-skripts-fuer-ibm-connections-administratorenICS User Group
 
Back to Basics – Webinar 2: Ihre erste MongoDB-Anwendung
Back to Basics – Webinar 2: Ihre erste MongoDB-AnwendungBack to Basics – Webinar 2: Ihre erste MongoDB-Anwendung
Back to Basics – Webinar 2: Ihre erste MongoDB-AnwendungMongoDB
 
Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...
Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...
Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...gedoplan
 
Überblick zu EF7 auf DevCon der Fox-Pro-Usergroup in Frankfurt, Nov 2015
Überblick zu EF7 auf DevCon der Fox-Pro-Usergroup in Frankfurt, Nov 2015Überblick zu EF7 auf DevCon der Fox-Pro-Usergroup in Frankfurt, Nov 2015
Überblick zu EF7 auf DevCon der Fox-Pro-Usergroup in Frankfurt, Nov 2015Manfred Steyer
 
DOAG: NoSQL with MySQL
DOAG: NoSQL with MySQLDOAG: NoSQL with MySQL
DOAG: NoSQL with MySQLFromDual GmbH
 
Microservices mit Rust
Microservices mit RustMicroservices mit Rust
Microservices mit RustJens Siebert
 
Einstieg in Xpath für SEO (Campixx2021)
Einstieg in Xpath für SEO (Campixx2021)Einstieg in Xpath für SEO (Campixx2021)
Einstieg in Xpath für SEO (Campixx2021)Sebastian Adler
 
Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...
Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...
Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...gedoplan
 
MySQL Performance Tuning für Oracle-DBA's
MySQL Performance Tuning für Oracle-DBA'sMySQL Performance Tuning für Oracle-DBA's
MySQL Performance Tuning für Oracle-DBA'sFromDual GmbH
 

Ähnlich wie Datenbankoptimierung für Ruby on Rails (20)

Von 0 auf 100 - Performance im Web
Von 0 auf 100 - Performance im WebVon 0 auf 100 - Performance im Web
Von 0 auf 100 - Performance im Web
 
Legacy WebApps mit AngularJS pimpen
Legacy WebApps mit AngularJS pimpenLegacy WebApps mit AngularJS pimpen
Legacy WebApps mit AngularJS pimpen
 
Dockerize It - Mit apex in die amazon cloud
Dockerize It - Mit apex in die amazon cloudDockerize It - Mit apex in die amazon cloud
Dockerize It - Mit apex in die amazon cloud
 
JavaScript Performance
JavaScript PerformanceJavaScript Performance
JavaScript Performance
 
Von Typo3 zu Plone - Ein Migrationsbericht
Von Typo3 zu Plone - Ein MigrationsberichtVon Typo3 zu Plone - Ein Migrationsbericht
Von Typo3 zu Plone - Ein Migrationsbericht
 
MongoDB für Java-Programmierer
MongoDB für Java-ProgrammiererMongoDB für Java-Programmierer
MongoDB für Java-Programmierer
 
MongoDB für Java Programmierer (JUGKA, 11.12.13)
MongoDB für Java Programmierer (JUGKA, 11.12.13)MongoDB für Java Programmierer (JUGKA, 11.12.13)
MongoDB für Java Programmierer (JUGKA, 11.12.13)
 
Entity Framework hinter den Kulissen
Entity Framework hinter den KulissenEntity Framework hinter den Kulissen
Entity Framework hinter den Kulissen
 
bccon-2014 adm01 tipps-und-skripts-aus-dem-leben-eines-ibm-connections-admins
bccon-2014 adm01 tipps-und-skripts-aus-dem-leben-eines-ibm-connections-adminsbccon-2014 adm01 tipps-und-skripts-aus-dem-leben-eines-ibm-connections-admins
bccon-2014 adm01 tipps-und-skripts-aus-dem-leben-eines-ibm-connections-admins
 
Tipps und Skripts aus dem Leben eines Connections Admins
Tipps und Skripts aus dem Leben eines Connections AdminsTipps und Skripts aus dem Leben eines Connections Admins
Tipps und Skripts aus dem Leben eines Connections Admins
 
NoSQL with MySQL
NoSQL with MySQLNoSQL with MySQL
NoSQL with MySQL
 
Icsug conf 14_tipps-und-skripts-fuer-ibm-connections-administratoren
Icsug conf 14_tipps-und-skripts-fuer-ibm-connections-administratorenIcsug conf 14_tipps-und-skripts-fuer-ibm-connections-administratoren
Icsug conf 14_tipps-und-skripts-fuer-ibm-connections-administratoren
 
Back to Basics – Webinar 2: Ihre erste MongoDB-Anwendung
Back to Basics – Webinar 2: Ihre erste MongoDB-AnwendungBack to Basics – Webinar 2: Ihre erste MongoDB-Anwendung
Back to Basics – Webinar 2: Ihre erste MongoDB-Anwendung
 
Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...
Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...
Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...
 
Überblick zu EF7 auf DevCon der Fox-Pro-Usergroup in Frankfurt, Nov 2015
Überblick zu EF7 auf DevCon der Fox-Pro-Usergroup in Frankfurt, Nov 2015Überblick zu EF7 auf DevCon der Fox-Pro-Usergroup in Frankfurt, Nov 2015
Überblick zu EF7 auf DevCon der Fox-Pro-Usergroup in Frankfurt, Nov 2015
 
DOAG: NoSQL with MySQL
DOAG: NoSQL with MySQLDOAG: NoSQL with MySQL
DOAG: NoSQL with MySQL
 
Microservices mit Rust
Microservices mit RustMicroservices mit Rust
Microservices mit Rust
 
Einstieg in Xpath für SEO (Campixx2021)
Einstieg in Xpath für SEO (Campixx2021)Einstieg in Xpath für SEO (Campixx2021)
Einstieg in Xpath für SEO (Campixx2021)
 
Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...
Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...
Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...
 
MySQL Performance Tuning für Oracle-DBA's
MySQL Performance Tuning für Oracle-DBA'sMySQL Performance Tuning für Oracle-DBA's
MySQL Performance Tuning für Oracle-DBA's
 

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