Anzeige:
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 15 von 16

Thema: Performancevergleich bei Count (Oracle,DB2,MaxDB)

  1. #1
    Registrierter Benutzer Avatar von Gaert
    Registriert seit
    09.05.2002
    Ort
    Nußloch
    Beiträge
    1.317

    Performancevergleich bei Count (Oracle,DB2,MaxDB)

    Hallo Zusammen,

    ich habe ein Programm entwickelt, mit dem ich auf SAP Systemen testen möchte wieviele Datensätze sich pro Tabelle in einem Mandanten befinden.

    Für nicht SAPler: die meisten Tabellen in einem SAP System sind Mandantenabhängig, d.h. das erste Feld im Primärschlüssel ist ein Feld in dem die Identifikationsnummer des Mandanten enthält.

    Ich habe das Programm SAP Systemen mit verschiedenen DBMS drunter getestet, und bin dabei auf erstaunliches gestoßen.

    Statement (CLIENT ist das Mandantenfeld - 1. Feld im Primärschlüssel):
    SELECT COUNT(*) FROM tabelle WHERE CLIENT = '123'

    Die Tabelle auf der ich das ausführe enthält ca. 50GB Daten (ohne Indizes).

    Bei DB2 dauert die Abfrage ca. 5 Minuten
    Bei Oracle ca. 35 - 45 Minuten
    Bei MaxDB über 24 Stunden (danach musste ich abbrechen)

    Ich habe auch Erfahrung mit MS SQL Server gesammelt... ich schätze ihn von der Performance her gleichauf mit Oracle.

    Die Hardware ist leider nicht ganz vergleichbar, allerdings sind die Unterschiede auch so enorm.
    Kann mir jemand erklären, wie die einzelnen Datenbanken technisch vorgehen um einen Count durchzuführen, und woher die unterschiedlichen Laufzeiten kommen?

    Kann man bei MaxDB was drehen um das zu optimieren?
    Was macht DB2 anders um solche Ergebnisse zu liefern?

    Gruß,

    Gaert




  2. #2
    Registrierter Benutzer
    Registriert seit
    22.06.1999
    Beiträge
    677
    Das sieht mir so aus als wenn DB2 die einzige Datenbank ist, die den Count über den Index macht. Wenn Du die Abfrage öfters machst, würde ich es bei PostgreSQL mal mit einem funktionalen Index auf COUNT(id) probieren. Keine Ahnung, welche der von Dir genannten Datenbanken funktionale Indizes können, aber es ist auf jeden fall einen Versuch wert.

  3. #3
    Registrierter Benutzer Avatar von Gaert
    Registriert seit
    09.05.2002
    Ort
    Nußloch
    Beiträge
    1.317
    Hallo Christoph,

    danke für deine Antwort.
    Oracle liest auch über den Index - bei MaxDB bin ich mir da nicht so sicher, müsste aber eigentlich auch...

    Aus irgendeinem Grund tut sich DB2 mit einem Count nicht so schwer wie Oracle oder MaxDB.

    Das mit dem Count(id) ist so ne Sache - Oracle und DB2 unterstützen es... aber SAPs OpenSQL Dialekt nicht - und direkt mit NativeSQL durch die Abstraktionsebene auf die DB zuzugreifen ist mir ein wenig zu heiß.

    Übrigens Danke für den Tipp mit PostgreSQL, aber die DB wird von SAP nicht unterstützt und steht daher nicht zur Diskussion.

    Gruß,

    Gaert
    Geändert von Gaert (07-05-2007 um 11:09 Uhr)


  4. #4
    Registrierter Benutzer
    Registriert seit
    07.05.2007
    Beiträge
    656
    Hallo,

    zu MaxDB kann ich nichts sagen, aber aus eigener Erfahrung weiss ich, dass Oracle gerade beim count(*) nicht unbedingt naheliegende Indizes verwendet. Man kann dem Optimizer aber über sog. Hints auf die Sprünge helfen. Das sieht dann ungefähr so aus (aus dem Gedächtnis, also besser nochmal nachschlagen):

    Code:
    select count(*) /*+ Tabelle Index */ from Tabelle where Spalte = Wert;
    hth
    Jan

  5. #5
    Registrierter Benutzer
    Registriert seit
    07.05.2007
    Beiträge
    656
    Zitat Zitat von jan61 Beitrag anzeigen
    Hallo,

    zu MaxDB kann ich nichts sagen, aber aus eigener Erfahrung weiss ich, dass Oracle gerade beim count(*) nicht unbedingt naheliegende Indizes verwendet. Man kann dem Optimizer aber über sog. Hints auf die Sprünge helfen. Das sieht dann ungefähr so aus (aus dem Gedächtnis, also besser nochmal nachschlagen):

    Code:
    select count(*) /*+ Tabelle Index */ from Tabelle where Spalte = Wert;
    hth
    Jan
    P.S.: (ich antworte mir selbst, weil der Ändern-Button sich offenbar mit sich selbst beschäftigt - kommt die SW mit Konqueror nicht zurecht?) - ich halte das für einen üblen Bug in Oracle - eine Abfrage mit identischer where-Bedingung, aber ohne count(*) kommt im Bruchteil der Zeit zurück. Kann man z. B. testen mit:
    Code:
    select * from Tabelle where Spalte = Wert and rownum < 50;

  6. #6
    Registrierter Benutzer
    Registriert seit
    15.10.2005
    Ort
    Franken
    Beiträge
    362
    Bei SAP nützen diese Hints nichts, da es Embedded SQL nutzt (zumindest ABAP).
    Ich hab die Querry bei uns auch mal durchlaufen lassen. 22 GB Daten auf MaxDB - abbruch nach 3 Stunden.
    Lösung:
    Nicht count(*) benutzen, sondern
    SELECT id FROM blabla WHERE client="blub"
    Und dann über die ABAP-Funktion die Anzahl der Werte auslesen.
    17 Minuten hat der Spaß gedauert.
    Dank der Rekursion kann ich IF-Schleifen bauen.

    In neuem Glanz: www.turbohummel.de

  7. #7
    Registrierter Benutzer Avatar von Gaert
    Registriert seit
    09.05.2002
    Ort
    Nußloch
    Beiträge
    1.317
    Zitat Zitat von Turbohummel Beitrag anzeigen
    Bei SAP nützen diese Hints nichts, da es Embedded SQL nutzt (zumindest ABAP).
    Ich hab die Querry bei uns auch mal durchlaufen lassen. 22 GB Daten auf MaxDB - abbruch nach 3 Stunden.
    Lösung:
    Nicht count(*) benutzen, sondern
    SELECT id FROM blabla WHERE client="blub"
    Und dann über die ABAP-Funktion die Anzahl der Werte auslesen.
    17 Minuten hat der Spaß gedauert.
    Ich habe versucht das nachzuvollziehen, aber bin leider nicht auf die selben Ergebnisse gekommen wie du.
    Die Tabelle mit der ich getestet habe ist AGR_HIERT (Texte zu Berechtigungen).
    Das ABAP Coding sieht so aus:
    Code:
    DATA: lt_clnt TYPE TABLE OF MANDT.
    DATA: lv_clnt TYPE MANDT.
    
    * Variante 1
                SELECT MANDT FROM AGR_HIERT
                  CLIENT SPECIFIED
                  INTO lv_clnt
                  WHERE MANDT = '800'.
                ENDSELECT.
    
    WRITE: / 'Anzahl Sätze:', sy-dbcnt.
    
    * Variante 2
                SELECT MANDT FROM AGR_HIERT
                  CLIENT SPECIFIED
                  INTO TABLE lt_clnt
                  WHERE MANDT = '800'.
    
    WRITE: / 'Anzahl Sätze:', sy-dbcnt.
    
    * Variante 3
                SELECT COUNT(*) FROM AGR_HIERT
                  CLIENT SPECIFIED
                  WHERE MANDT = '800'.
    
    WRITE: / 'Anzahl Sätze:', sy-dbcnt.
    Varianten 1 und 2 sind bei mir sehr viel langsamer als Variante 3...

    Die Datenbank ist Oracle 8.1.7.0.0 (das System ist ein 4.6C IDES)

    Kannst du das Beispiel vielleicht bei dir mal nachvollziehen?

    Gruß,

    Gaert
    Geändert von Gaert (10-05-2007 um 15:32 Uhr)


  8. #8
    Registrierter Benutzer
    Registriert seit
    15.10.2005
    Ort
    Franken
    Beiträge
    362
    Genau so gemacht (Allerdings mit der BANF-Tabelle).
    Die anderen Datenbanken hab ich nicht im Zugriff.

    Vielleicht irgendein Konfigurationsfehler? Wenig Ram? (MaxDB scheint mir recht RAM-Lastig zu sein im Vergleich zu DB2 (Oracle hab ich nie getestet).

    Hast du die Abfrage mal über ein Abfrage-Tool losgelassen? Nur so um zu testen. Vielleicht läuft der SQL-Wrapper irgendwie Amok.
    Dank der Rekursion kann ich IF-Schleifen bauen.

    In neuem Glanz: www.turbohummel.de

  9. #9
    Registrierter Benutzer Avatar von Gaert
    Registriert seit
    09.05.2002
    Ort
    Nußloch
    Beiträge
    1.317
    Hallo,

    ich habe mal einen kleinen Report zum testen gebaut:

    Code:
    PARAMETERS P_TAB TYPE DD02l-TABNAME.
    
    DATA: f1   TYPE INT4.
    DATA: f2   TYPE INT4.
    
    DATA: t1   TYPE INT4.
    DATA: t2   TYPE INT4.
    
    DATA: lv_time TYPE INT4.
    
    DATA: TF2   TYPE TABLE OF mandt.
    
    
    DO 5 TIMES.
    
      GET RUN TIME FIELD f1.
      SELECT MANDT FROM (P_TAB)
       CLIENT SPECIFIED
       INTO TABLE TF2
       PACKAGE SIZE 1000000
       WHERE MANDT <> '800'.
        CLEAR TF2[].
      ENDSELECT.
      GET RUN TIME FIELD f2.
    
      WRITE: / 'SELECT'.
      lv_time = f2 - f1.
      WRITE: / lv_time, 'msec'.
    
      GET RUN TIME FIELD t1.
      SELECT COUNT(*) FROM (P_TAB) CLIENT SPECIFIED WHERE MANDT <> '800'.
      GET RUN TIME FIELD t2.
    
      WRITE: / 'COUNT(*)'.
      lv_time = t2 - t1.
      WRITE: / lv_time, 'msec'.
    
    
    ENDDO.
    
    WRITE: / sy-dbcnt, 'Sätze'.
    Die Ausgabe ist wie folgt... (Oracle)

    Code:
    SELECT              
    9.562.668  msec     
    COUNT(*)            
      997.379  msec     
    SELECT              
    2.496.473  msec     
    COUNT(*)            
      793.977  msec     
    SELECT              
    2.607.573  msec     
    COUNT(*)            
      796.406  msec     
    SELECT              
    2.588.213  msec     
    COUNT(*)            
      798.658  msec     
    SELECT              
    2.861.512  msec     
    COUNT(*)            
      848.646  msec     
       600.244  Sätze
    Auf einem anderen System (MaxDB) gabs bei einer ähnlichen Tabelle folgendes Ergebnis:
    Code:
    SELECT              
    7.817.943  msec     
    COUNT(*)            
    7.576.127  msec     
    SELECT              
    9.258.830  msec     
    COUNT(*)            
    10033.309  msec     
    SELECT              
    7.908.668  msec     
    COUNT(*)            
    10525.332  msec     
    SELECT              
    8.287.411  msec     
    COUNT(*)            
    9.287.431  msec     
    SELECT              
    7.542.867  msec     
    COUNT(*)            
    8.780.092  msec     
       616.483  Sätze
    Die Datenbanken arbeiten also grundsätzlich verschieden... interessant ist, dass die Hardware des MaxDB Systems vom Prozessor her eigentlich stärker ist (aber ein bisschen weniger RAM).

    Die Zugriffszeiten bei MaxDB sind eigentlich alle schrott... bei Oracle lädt er die Tabelle wohl erstmal in den Speicher und greift dann je nach Verfahren unterschiedlich zu.

    Gruß,

    Gaert
    Geändert von Gaert (11-05-2007 um 11:39 Uhr)


  10. #10
    Registrierter Benutzer
    Registriert seit
    15.10.2005
    Ort
    Franken
    Beiträge
    362
    Prozessor ist bei großen Datenbanken nur selten das Nadelöhr. Das liegt im Raid btw im RAM. Richtig Spaß macht das bei MaxDB mit großen Tabellen erst so ab 8 Gig (meine dass wir das drin haben, bin mir nicht ganz sicher).

    Unsere IT hat mir folgendes Buch empfohlen:
    http://www.sap-press.de/katalog/buec...p/titelID-1155
    MaxDB soll in der Standard-Config wohl wirklich recht langsam sein, weil es alles von der Platte holt und nichts im Ram behält (so die IT), das lässt sich aber konfigurieren.
    Dank der Rekursion kann ich IF-Schleifen bauen.

    In neuem Glanz: www.turbohummel.de

  11. #11
    Registrierter Benutzer
    Registriert seit
    27.12.2002
    Ort
    Matrix
    Beiträge
    194
    Zitat Zitat von Gaert Beitrag anzeigen
    Statement (CLIENT ist das Mandantenfeld - 1. Feld im Primärschlüssel):
    SELECT COUNT(*) FROM tabelle WHERE CLIENT = '123'

    Die Tabelle auf der ich das ausführe enthält ca. 50GB Daten (ohne Indizes).

    Bei DB2 dauert die Abfrage ca. 5 Minuten
    Bei Oracle ca. 35 - 45 Minuten
    Bei MaxDB über 24 Stunden (danach musste ich abbrechen)
    zu oracle:

    in 35-45min liest Oracle auf halbwegs vernünftiger hardware (mein laptop reicht schon) die ganze 50g-tabelle, d.h. kein indexzugriff. wieviele zeilen ingesamt und wieviele davon fallen in die ergebnismenge? wieviele clients ingesamt in der tabelle? am besten mal ein histogramm mit 'select client, count(*) from tab group by client' erstellen.
    nr.1 problem sind immer wieder fehlende oder falsche statistiken. verfügt die tabelle über aktuelle oder korrekte statistiken?

    -j

  12. #12
    Registrierter Benutzer Avatar von Gaert
    Registriert seit
    09.05.2002
    Ort
    Nußloch
    Beiträge
    1.317
    Hallo Zusammen,

    vielen Dank für die Antworten.

    @Turbohummel: Danke für den Tipp mit dem Buch - das kenne ich schon.
    @Jasper: Ich nehme an, dass die Statistiken aktuell waren - in der Untersuchten Tabelle waren nur Daten aus einem Mandanten - es hätte aber durchaus möglich sein können, dass mehrere Mandanten drin sind.

    Grundsätzlich: Ich habe keinen Zugriff auf die Konfiguration der Systeme und ich weiß auch im Vorfeld nicht wieviele Mandanten das System hat... Ich bin dafür zuständig, dass die Software bei unseren Kunden auf allen Konfigurationen und DBMS vernünftig läuft.

    Vielleicht noch eine kurze Hintergrundinfo warum ich die Datensätze Zählen muss:
    Es geht darum sehr viele Daten selektiv von einem System in ein anderes zu migrieren. Bevor die Daten kopiert werden, wird eine Simulation gestartet, welche die zu kopierenden Datensätze zählt.
    Um den benötigten Speicherplatz auf dem Ziel zu berechnen brauche ich im Vorfeld eine Aussage wieviel Bytes ein Datensatz durchschnittlich pro Tabelle auf der Festplatte belegt (die Größe der Tabelle lese ich mir aus den Statistiken der Quelle und teile sie durch die Anzahl aller Datensätze in der Tabelle (Mandantenübergreifend)).
    Zusätzlich benötige ich die Anzahl der Sätze im Mandanten als Entscheidungsgrundlage um festzulegen, ob eine Tabelle komplett oder in teilen kopiert werden soll.
    D.h. ich muss zweimal zählen, einmal mandantenübergreifend und einmal mandantenabhängig...

    Vielleicht fällt euch aber auch ein Trick ein, wie ich schneller herausfinde wieviele Bytes ein Datensatz bei Oracle, MaxDB oder DB2 wirklich auf der Festplatte belegt?
    Geändert von Gaert (14-05-2007 um 12:09 Uhr)


  13. #13
    Registrierter Benutzer
    Registriert seit
    27.12.2002
    Ort
    Matrix
    Beiträge
    194
    Zitat Zitat von Gaert Beitrag anzeigen
    Um den benötigten Speicherplatz auf dem Ziel zu berechnen brauche ich im Vorfeld eine Aussage wieviel Bytes ein Datensatz durchschnittlich pro Tabelle auf der Festplatte belegt (die Größe der Tabelle lese ich mir aus den Statistiken der Quelle und teile sie durch die Anzahl aller Datensätze in der Tabelle (Mandantenübergreifend)).
    oracle:
    anzahl der datensätze:
    select num_rows from all_tab_statistics where owner=? and table_name=?

    grösse der tabelle:
    select a.blocks*b.block_size from all_tab_statistics a join b.dba_tablespaces on a.owner = b.owner and a.tablespace_name = b.tablespace_name where a.owner =? and a.table_name=?

    durchschnittliche grösse eines datensatzes:
    select avg_row_len from all_tab_statistics where owner=? and table_name=?

    alle werte bedingen korrekte statistiken. am besten prüfen mit

    select stale_stats from all_tab_statistics where owner=? and table_name=?
    select monitoring from all_tables where owner=? and table_name=?
    select last_analyzed from all_tab_statistics where owner=? and table_name=?

    erstes sollte 'N' ergeben, zweiteres 'Y'. falls zweiteres 'N' ergibt, last_analyzed verwenden.

    Zusätzlich benötige ich die Anzahl der Sätze im Mandanten als Entscheidungsgrundlage um festzulegen, ob eine Tabelle komplett oder in teilen kopiert werden soll.
    D.h. ich muss zweimal zählen, einmal mandantenübergreifend und einmal mandantenabhängig...
    einmal zählen reicht:

    select client, count(*) from tabelle group by rollup(client)

    Vielleicht fällt euch aber auch ein Trick ein, wie ich schneller herausfinde wieviele Bytes ein Datensatz bei Oracle, MaxDB oder DB2 wirklich auf der Festplatte belegt?
    siehe oben: blocks*block_size/num_rows


    -j

  14. #14
    Registrierter Benutzer Avatar von Gaert
    Registriert seit
    09.05.2002
    Ort
    Nußloch
    Beiträge
    1.317
    Hallo Jasper,

    erstmal vielen Dank... das mit dem ROLLUP ist eine sehr gute Idee!

    Das Auslesen der Statistiken funktioniert auf der hier installierten Oracle 8 so leider nicht - ich nehme an, da heißen die Systemtabellen anders - irgendeine Idee?
    Googeln hat leider nichts gebracht ich find immer nur Hilfen für 10g...

    Gruß,

    Gaert


  15. #15
    Registrierter Benutzer Avatar von Gaert
    Registriert seit
    09.05.2002
    Ort
    Nußloch
    Beiträge
    1.317
    Habs gefunden... der View heißt hier DBA_ALL_TABLES statt all_tab_statistics.
    Die Frage ist, gibts den unter Oracle 9 und 10 auch?

    Gruß,

    Gaert


Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •