Anmelden

View Full Version : Schlechte SQL Performance bei Join?



Seiten : 1 [2] 3

andreaspr@aon.at
07-08-10, 16:55
Hallo Holger,
wie Du weißt bin ich ein Fan der schwarzen Kiste, aber ich hatte gehofft das die Kiste im direketen Vergleich zu mysql besser ist ohne das man PTF Stand und intime Kenntnisse der QueryEngine haben muß.
Das man mit dem Wissen von Birgitta mehr aus der Kiste rausholen kann ist schon klar aber auch einer wie ich sollte damit glücklich werden.

GG

Hi KingofKning,
bin da ganz deiner Meinung.
Ich glaube aber nicht, dass die beiden DB-Systeme ident sind. Oracle ist eine DB die man mit einer DB2 vergleichen kann, aber MySQL und das mit so einem großen unterschied?? Da könnten wir ja gleich MS-Access gegen die DB2 antreten lassen.
Da wird mit Sicherheit irgendwas sein was extrem bremst. Eventuell Primärschlüsseln die bei MySQL vorhanden sind und bei der DB2 nicht? Dadurch hätte MySQL gegen der DB2 einen (nicht unwesendlichen) Vorteil.
Deshalb würde ich auch (wie ich auch schon oben geschrieben habe) nachschauen was der Flaschenhals ist und dann sieht man schon genaueres.

Eventuell sind die Einstellungen in der QAQQINI nicht korrekt. Schaun obs in der QUSRSYS eine QAQQINI gibt und welche Werte die hat. Wenn in der Lib eine vorhanden ist wird die nämlich als für alle SQL-Anweisungen als Default hergenommen.

Noch ein kleiner Tipp: Egal ob mit SQL oder Native I/O bei DDS Tabellen werden die Daten nur beim Lesen geprüft und bei SQL-Tabellen nur beim Schreiben. Da mehr gelesen wird als geschrieben sind SQL-Tabellen auch Performanter.

BenderD
08-08-10, 09:11
... ich meine schon, was ich schreibe!
zur Problemstellung:
ich gehe mal davon aus, dass DBTEXT nicht klein ist und MATINDEX um etliches größer und dass die Ergebnismenge eine hohe Selektivität hat, also um ein Vielfaches kleiner als DBTEXT ist. (right oder left join ist hier verkehrt!!! das ist ein klassischer Fall für einen inner join).

Wenn obige Konstellation stimmt, hast du zwei Möglichkeiten:
1. den Index auf das Sortierfeld zu löschen (falls der anderweitig nicht benötigt wird)
2. Zweistufig arbeiten und im ersten Schritt ein Substrat ziehen (create table qtemp.ddd as (select ... from... !!! ohne order by!!!) und im zweiten Schritt select * from qtemp.ddd order by...)
Das auch denkbare Festschreiben der Join Reihenfolge per QAQQINI könnte auch klappen, würde ich aber lassen, das macht andere Queries kaputt.

Dass da eine Datenbank schneller als die andere sein kann, unabhängig von den Lizenzkosten, liegt daran, dass auf unterschiedliche Ziele optimiert wird - jede Datenbank hat ihre Stärken und Schwächen, die in einem inneren Zusammenhang stehen und da liegt es bei MySQL (bei der Abwesenheit von Lizenzkosten) schon nahe für eine spezifische Aufgabe, wenn sie denn kritisch ist, sich das Beste aus mehreren Welten zusammen zu packen!

D*B



Moment - Dieters Sätze sind manchmal mit einer gewissen Vorsicht zu geniessen, ein wenig Ironie und Bissigkeit kann schon dabei sein. Da ich gerade neben ihm sitze, gehe ich davon aus, dass das nicht seine ultimative Meinung zur Lösung des Problems ist. Aber wie geschrieben, nun brauchts Detailinfos.

Nachtrag: ich werde so aus dem zweiten Blick nicht schlau, was Du genau aus welchen Dateien holst. Könntest Du die beiden Dateien genau beschreiben, was wo liegt, und *wann* Du welche Sätze mit welcher Kondition Verknüpfung holen willst. Und - bei solchen Dingen - ist Releasestand und PTF-Stand wichtig.


-h

BenderD
08-08-10, 10:13
... das ist eines dieser Märchen, die ungeprüft von einem zum anderen weiter erzählt werden (sorry, dass es dich jetzt mit meiner Antwort erwischt). Dieser Mythos geht zurück auf einen Artikel von Dan Cruikshank, der vom IBM Marketing weiter verbreitet wird (http://www-03.ibm.com/systems/resources/systems_i_software_db2_pdf_Performance_DDS_SQL.pdf ), obwohl er der DB2/400 ein verheerendes Zeugnis ausstellt: das würde nämlich bedeuten, dass bei einer beschädigten Tabelle aus einer SQL Tabelle jeder beliebige Dreck hochkäme...
Ich habe mir das bereits bei erscheinen mal näher angesehen:
- die Maschine hungert (muss eine alte Möhre sein) die braucht für einen read so um die 3 Millisekunden
- CPU Verbrauch ist bei SQL und DDL ziemlich identisch (und welche Ressource braucht Prüfung?)
- die Verarbeitungszeit ist klar durch "Waits" dominiert (99%), was in diesem Fall I/O bedeutet.
Schlussfolgerung: die Begründung für die Zeitunterschiede ist glasklar falsch (Dummfug, der Dummfugigsten Sorte, würde Fred Feuerstein sagen). Was näher liegt ist, dass sich die Blockgrößen beim lesen unterscheiden, ist aber spekulativ.

Kommen wir zu den Zeitunterschieden und deren Relevanz:
Auffallend sind auf den ersten Blick die seltsamen Skalierungen und die unterschlagenen Differenzen. Die Gesamtlaufzeit der Testprogramme differiert von 21 zu 25 sec, der Teil für die Leseschleife von 15 zu 26. Selbst wenn ich jetzt annehme, dass die Unterschieder korrekt und typisch wären, ergibt sich im vorliegenden Fall, dass aus den 2 Sekunden (lesen ohne order by) 1,5 Sekunden würden, die 20 Sekunden würden dann auf 19,5 Sekunden abnehmen.

Konsequenz 1: glaube keiner Benchmark, die du nicht selber gefälscht hast!
Konsequenz 2: Es gibt keine Patentrezepte (die wären dann schon eingebaut)

D*B


Noch ein kleiner Tipp: Egal ob mit SQL oder Native I/O bei DDS Tabellen werden die Daten nur beim Lesen geprüft und bei SQL-Tabellen nur beim Schreiben. Da mehr gelesen wird als geschrieben sind SQL-Tabellen auch Performanter.

andreaspr@aon.at
08-08-10, 12:29
... (sorry, dass es dich jetzt mit meiner Antwort erwischt).
...
Konsequenz 1: glaube keiner Benchmark, die du nicht selber gefälscht hast!
Konsequenz 2: Es gibt keine Patentrezepte (die wären dann schon eingebaut)

Da wir alle hier sind damit wir auch was lernen können, habe ich mit der Antwort auch kein Problem.
Ich selbst bin mit der Zeit sehr vorsichtig geworden zu behaupten was falsch und was richtig ist, wenn ich es nicht zu 99% weis!
Das Beispiel in dem 4 Tabellen erstellt werden (2 DDS & 2 SQL, je eine Tabelle mit einer Dec-Spalte und die andere Tabelle mit einer Char-Spalte) zeigt für mich, dass ich in eine DDS-Tabelle (Spalte Numeric 7 0) sehrwohl Werte aus einem Char-Feld hinzufügen kann. Auch wenn es sich um alphanummerische Werte handelt.
CPYF FROMFILE(TESTLIB/T1) TOFILE(TESTLIB/T2) MBROPT(*ADD) FMTOPT(*NOCHK)
Bei SQL-Tabellen geht das zwar auch, jedoch gibt es (im gegensatz zu DDS) EINE Fehlermeldung, wenn im Char-Feld keine nummerisch genormte Zeichenfolge enthalten ist.
Das ist kein Voodoo und kann auch jeder ausprobieren und testen.
Von dem her bedarf es schon einer sehr, sehr guten Erklärung, dass DAS nicht so ist wie es ist!
Wie sehr sich das auf die Performance auswirkt sei dahingestellt. Habe leider selbst noch keine aussagekräftige Benchmarks machen können.

BenderD
08-08-10, 12:49
... in meinem Beitrag ging es klar um den Teil des lesens der Tabelle und um die Behauptung, dass SQL erstellte Tabellen Perfomancevorteile wegen - !!!andersartiger Prüflogik!!! - hätten. Wenn dich das tiefer interessiert - da ist noch mehr krumm, die Prüfung beim record level access erfolgt erst nach dem lesen, im Programm, beim übertragen der Felder (merkt man, wenn man mit Programm interner Beschreibung liest).

D*B



Da wir alle hier sind damit wir auch was lernen können, habe ich mit der Antwort auch kein Problem.
Ich selbst bin mit der Zeit sehr vorsichtig geworden zu behaupten was falsch und was richtig ist, wenn ich es nicht zu 99% weis!
Das Beispiel in dem 4 Tabellen erstellt werden (2 DDS & 2 SQL, je eine Tabelle mit einer Dec-Spalte und die andere Tabelle mit einer Char-Spalte) zeigt für mich, dass ich in eine DDS-Tabelle (Spalte Numeric 7 0) sehrwohl Werte aus einem Char-Feld hinzufügen kann. Auch wenn es sich um alphanummerische Werte handelt.
CPYF FROMFILE(TESTLIB/T1) TOFILE(TESTLIB/T2) MBROPT(*ADD) FMTOPT(*NOCHK)
Bei SQL-Tabellen geht das zwar auch, jedoch gibt es (im gegensatz zu DDS) EINE Fehlermeldung, wenn im Char-Feld keine nummerisch genormte Zeichenfolge enthalten ist.
Das ist kein Voodoo und kann auch jeder ausprobieren und testen.
Von dem her bedarf es schon einer sehr, sehr guten Erklärung, dass DAS nicht so ist wie es ist!
Wie sehr sich das auf die Performance auswirkt sei dahingestellt. Habe leider selbst noch keine aussagekräftige Benchmarks machen können.

andreaspr@aon.at
08-08-10, 16:10
... in meinem Beitrag ging es klar um den Teil des lesens der Tabelle und um die Behauptung, dass SQL erstellte Tabellen Perfomancevorteile wegen - !!!andersartiger Prüflogik!!! - hätten. Wenn dich das tiefer interessiert - da ist noch mehr krumm, die Prüfung beim record level access erfolgt erst nach dem lesen, im Programm, beim übertragen der Felder (merkt man, wenn man mit Programm interner Beschreibung liest).

D*B

Wie ich geschrieben habe, kann ich über die Performance nichts sagen, damit könntest du auch recht haben. Ich will nur nicht, dass jetzt jeder glaubt, dass die Prüfung wie ich sie beschrieben habe von den Lesern auch als Mythos verstanden wird.

cbe
08-08-10, 22:26
Hallo allerseits!

... 2. Zweistufig arbeiten und im ersten Schritt ein Substrat ziehen (create table qtemp.ddd as (select ... from... !!! ohne order by!!!) und im zweiten Schritt select * from qtemp.ddd order by...)

hier stimme ich Dieter voll zu, das zweistufige Arbeiten hat mir auch schon deutlich Laufzeit gespart.
Ich mag allerdings dabei keine Objekte explizit erstellen, WITH ist mir sympatischer, und das geht auch mehrstufig:


with x as (
select IXFNAM, IXTEXT, IXRECL from matindex
where
IXFNAM = 'DBTEXT'
and IXTEXT = 'KUNDE'),
y as (SELECT
'DBTEXT', PDPRN2, PDPRN3, PDKDK, PDMA, PDBTDT,
rtrim(PDTXT1)||rtrim(PDTXT2)||rtrim(PDTXT3)||
rtrim(PDTXT4)||rtrim(PDTXT5) as Txt
FROM DBTEXT right join x on IXRECL = PDLFDN)
select 'DBTEXT', PDPRN2, PDPRN3, PDKDK, PDMA, PDBTDT, Txt
FROM y order by pdbtdt


(Ich hoffe, die Syntax stimmt so...)

Hiermit erzwingt man, dass das Sortieren erst am Schluss gemacht wird, was manchmal sparsamer ist.
Würde mich interessieren, ob es hier auch hilft.

Ob der Right-Join hier Sinn macht usw. will ich gar nicht weiter ansprechen, das wurde ja schon diskutiert.

Gruß, Christian

BenderD
09-08-10, 07:45
... frei nach Theorie zieht der Optimizer das gesamte SQL Statement zur Optimierung heran, arbeitet also nach dem Prinzip: entscheidend ist, was hinten rauskommt. Hier hält sich ein weiterer Mythos hartnäckig, das die Performance einer Abfrage von der geschickten Formulierung abhänge. Wenn sich der Optimizer von der Art der Formulierung der gleichen Abfrage (:= gleiches Ergebnis!) beeindrucken lässt, dann ist das ein Bug im Sinne von SQL (da zähle ich auch die Existenz zweier Query Engines dazu, die unter sich auswürfeln wer dran ist), oder ein Seiteneffekt des Nebenkriteriums des Optimizers: der nimmt das aktuell best bewerteteste Ergebnis, wenn ihm das gut genug ist, oder lange genug gesucht wurde.

Mehrstufigkeit wird also durch with Formulierungen nur zufällig erreicht, eine temporäre Tabelle erzwingt das. Ich bin kein Freund davon, aber damit kann man Teile mit hoher Selektivität (kleine Trefferzahl) vorziehen, um damit Abfragen zu beschleunigen.

Für die Ausgangslage, da könnte noch das parallel Database Feature weiterhelfen (nicht billig!), das verschiebt die Optimierung in die Richtung, die hier gebraucht wird.

D*B



Hallo allerseits!

hier stimme ich Dieter voll zu, das zweistufige Arbeiten hat mir auch schon deutlich Laufzeit gespart.
Ich mag allerdings dabei keine Objekte explizit erstellen, WITH ist mir sympatischer, und das geht auch mehrstufig:


with x as (
select IXFNAM, IXTEXT, IXRECL from matindex
where
IXFNAM = 'DBTEXT'
and IXTEXT = 'KUNDE'),
y as (SELECT
'DBTEXT', PDPRN2, PDPRN3, PDKDK, PDMA, PDBTDT,
rtrim(PDTXT1)||rtrim(PDTXT2)||rtrim(PDTXT3)||
rtrim(PDTXT4)||rtrim(PDTXT5) as Txt
FROM DBTEXT right join x on IXRECL = PDLFDN)
select 'DBTEXT', PDPRN2, PDPRN3, PDKDK, PDMA, PDBTDT, Txt
FROM y order by pdbtdt


(Ich hoffe, die Syntax stimmt so...)

Hiermit erzwingt man, dass das Sortieren erst am Schluss gemacht wird, was manchmal sparsamer ist.
Würde mich interessieren, ob es hier auch hilft.

Ob der Right-Join hier Sinn macht usw. will ich gar nicht weiter ansprechen, das wurde ja schon diskutiert.

Gruß, Christian

Pikachu
09-08-10, 10:27
Leg mal eine logische Datei für DBTEXT mit einem Zugriffspfad über die Spalten PDLFDN und PDBTDT an und probier dann mal mit ORDER BY PDLFDN, PDBTDT.

schatte
14-08-10, 19:02
Leg mal eine logische Datei für DBTEXT mit einem Zugriffspfad über die Spalten PDLFDN und PDBTDT an und probier dann mal mit ORDER BY PDLFDN, PDBTDT.

Hallo Pikachu,

das geht dann flott. Aber es ist ja dann nicht mehr nach dem Datum (PDBTDT) sortiert.

@Holger: In der Datei DBTEXT sind 800.000 Sätze enthalten. Es enthält 5 Textspalten (PDTXT1 - 5 jeweils 50 Stellen lang), eine eindeutige laufende Nummer (PDLFDN), ein Datumsfeld (PDBTDT). Nun möchte ich die Textspalten per Freitextselektion durchsuchen. Damit ich nicht jeden Datensatz mit SQL UCASE(TEXT) Like '%SUCHBEGRIFF%' prüfen muss, lasse ich jeden Abend eine Wort Indexierung erstellen (Tabelle MATINDEX). Jedes Wort wird dabei in Großschrift in die Datei MATINDEX geschrieben mit einem Bezug auf die laufende Nummer (PDLFDN) der Datei DBTEXT.

Bisher hatte ich für die Abfrage ein Cobol Programm erstellt, was für den Suchbegriff jeweils die Sätze aus der MATINDEX liest und die dazugehörigen DBTEXT Datensätze in ein Sortfile einliest, damit nach PDBTDT sortiert werden kann.

Dieses Cobolprogramm wollte ich nun durch ein SQL Cobolprogramm ersetzen.


Gruß
Matthias