View Full Version : SQL Performance Probleme im Batch
... zuerst muss man wissen was die Query Engine da so treibt, deshalb der STRDBMON, der protokolliert das mit *DETAIL raus (kostet < 1% Laufzeit, aber ziemlich viel Platten Platz). Diese Messung sollte man im Echtbetrieb mitlaufen lassen. Dann startet man den seefahrenden Chirurgen (Operations Navigator, oder wie das Teil gerade mal heißt) da gibt es einen Database Dingensbumens; da muss man dann die Messdaten importieren und sieht sich dann die Einzelstatement Ebene (absteigend sortiert nach Laufzeit) an. Wenn man ein wenig vertraut damit ist, findet man auch Informationen über Zugriffsplan: Interaktiv schnell und Batch langsam sieht nach full table scan, oder irgendwas anderem raffinierten aus, da hilft dann oft ein passender order by für die Ergebnismenge.
Bei großen Datenmengen (ein paar hundert Millionen) ist es im Batch oft vorteilhaft, zuerst temporäre Extracte zu ziehen, die man dann weiter verarbeitet, wenn die Anwendungslogik das zulässt.
D*B
So ich habe Neuigkeiten, die mich noch mehr verzweifeln lassen.:(
Ich konnte das Problem lokalisieren und habe folgendes gemacht: Das Programm wo nachts läuft habe ich jetzt aufgerufen und siehe da, das SQL dauert.
Ich hatte geschrieben, dass es am Tag schnell läuft, bezieht sich aber auf andere Parameter, sorry.
Script Auszug:
c/exec sql
c+ prepare s1 from :W@SqlStr
c/end-exec
**
c/EXEC SQL
c+ DECLARE CRS1SQL CURSOR FOR S1
c/END-EXEC
**
**
c/EXEC SQL
c+ OPEN CRS1SQL
c/END-EXEC
**
**EXEC SQL
** WHENEVER NOT FOUND GOTO SbSQLEnd
**END-EXEC
c do *hival
c/EXEC SQL
c+ FETCH NEXT FROM CRS1SQL INTO :INPSQL
c/END-EXEC
**
c
**
c if SqlCod < *zero or SqlCod = 100
c leave
c endif
Das Programm bleibt auf den END-EXEC nach dem FETCH ca, 10 Minuten stehen und zieht CPU. Im wrkactjob steht der Job auf RUN und keine IO Operation in der DB.
Habe den STRDBMON aufgesetzt und der sagt, dass alles gut ist. Bevor das Programm stehen blieb waren 54 Sätze in der outfile und danach auch, d.h. der letzte Eintrag war schon vorher da. Da steht auch Start-Time und End-Time. Nur was macht er solange.
Im debug steht, dass alle Indizes genommen wurden.
Gruß Klaus
Wo bleibt er stehen?
Nach dem FETCH oder nach dem OPEN?
Ich schätze mal, nach dem OPEN, d.h. das Öffnen des ODPs dauert sehr lange.
Auch wenn Zugriffswege verwendet werden, heißt das noch lange nicht, dass die korrekten Zugriffswege auch vorhanden sind.
M.E. werden temporäre Zugriffswege/Indices benötigt und erstellt. Das würde die lange Laufzeit und dass CPU ohne Ende gezogen wird erklären. Nachdem die/die temporären Indices erstellt sind, sollte die Verarbeitung sehr schnell erfolgen.
Zunächst sollte geprüft werden, ob und wenn ja welche (temporären) Indices erstellt werden müssen. Diese Zugriffswege sollten dann als permanente Zugriffswege/Indices erstellt werden.
Nachdem die Erstellung der temporären Indices wohl jedes Mal (also in jedem Job) in dem die Abfragen ausgeführt werden durchgeführt werden, ist davon auszugehen, dass die alte/classic Query Engine die Abragen ausführt.
Bevor Indices angelegt werden, sollte versucht werden die Abfragen durch die SQE ausführen zu lassen und anschließend neu zu analysieren.
Muss die Abfrage wirklich dynamisch zusammengesetzt werden?
Das macht die Analyse ziemlich schwierig, da das exakte SQL-Statement zunächst herausgepullt werden muss.
Allerdings ohne die SQL-Statements und die Ergebnisse aus dem Database Monitor zu kennen, kann an dieser Stelle nur geraten werden.
Der Database Monitor kann auch über den IBM i Navigator gestartet werden (über SQL Performance Monitor). Über den IBM i Navigator können die gesicherten Informationen aus dem Performance Monitor ausgewertet werden.
Birgitta
Hallo Brigitta,
habe ich mich so undeutlich ausgedrückt?, sorry! Der Cursor bleibt bei dem END-EXEC nach dem Fetch stehen. Der DBMONITOR zeigt mir als Ergebnis eine Antwortzeit von 100 ms. Wie schon geschrieben, in der Outfile vom DBMONITOR stehen 54 Datensätze und alle sind im ms Bereich.
Ich habe nun einen TRCJOB gemacht. Die Zeit wird verbraten im PGM/Modul QDBGETMQ0.
Das Programm bleibt auf den END-EXEC nach dem FETCH ca, 10 Minuten stehen und zieht CPU. Im wrkactjob steht der Job auf RUN und keine IO Operation in der DB.
hast du mit f15 auf die sqlsicht umgeschaltet?
Hier der Auszug vom Trace:
15:35:57.305763 00001796 RETURN QDBGETMQO QSYS 003099 003004 14 .000000 0 0 0
MODULE QDBGETMQO QBUILDSS1
PROC QDBGETMQO
15:47:08.269430 00001796 CALL QDBGETMQO QSYS 000000 003807 15 411.509978 663 19 0
MODULE QDBGETMQO QBUILDSS1
Hier sieht man, dass 411 CPU Sekunden in dem Modul vergehen.
hast du mit f15 auf die sqlsicht umgeschaltet?
danke, noch ein guter Tip. Wusste gar nicht, dass es da gibt.
Der Cursor steht auf CALL SQLROUTE.
c/END-EXEC
C Z-ADD -4 SQLER6
C CALL SQLROUTE
C PARM SQLCA
C PARM SQL_00006
C SQL_00009 IFEQ '1'
C EVAL IFILE = SQL_00011
... solange der im QDBGETMQO ist, wird vom DBMON auch nix geschrieben. spannend wird es allenfalls, sobald der davon zurückkommt, wenn er das tut und nicht über irgendeinen schwindeligen timeout rausfliegt und fertig ist... jedenfalls liefert google nach QDBGETMQO massig PTFs hast Du schon bug report gemacht und Software defect reklamiert?
D*B
Der QDBGETMQ0 erstellt wohl eine "Materialized Query Table" was je nach Umfang schon mal dauert.
Interessant wäre also wirklich, wie dein dynamischer SQL denn aussieht.
Auch wenn Indizes genommen werden heißt das nicht, dass das schnell gehen muss.
Es kommt halt auf de Datenmenge an.
select a.f1, b.f1
from filea a
inner join fileb b on a.key=b.key
where a.x1 = 'X' and b.x1 >= 'Y' and b.x2 <> 'Z'
Wenn nun in filea der Wert X 1.000 mal vorkommt und in fileb der wert Y nur 10 mal, müssen trotzdem die 1000 Sätze gelesen werden um die 990 über fileb wieder auszuschließen.
Je nach dem wie viele Joins du so bemühst, können durchaus mehrere Millionen Zugriffe (trotz Index) entstehen.
Ein Index hilft dann wirklich nicht so viel weiter, da die Anzahl Leseoperation über mehrere Tabellen einfach mal dauert.
... solange der im QDBGETMQO ist, wird vom DBMON auch nix geschrieben. spannend wird es allenfalls, sobald der davon zurückkommt, wenn er das tut und nicht über irgendeinen schwindeligen timeout rausfliegt und fertig ist... jedenfalls liefert google nach QDBGETMQO massig PTFs hast Du schon bug report gemacht und Software defect reklamiert?
D*B
ja, da sind wir dran.
Ich habe jetzt das SQL nochmals analysiert und habe das Problem gefunden:
'AND DNHID IN (SELECT CDIDNID FROM CDICTLP '
'WHERE CDIBAID = 0 AND CDISHID = '' '') '
In der Datei CDICTLP gibt es 148000 Datensätze und in der Datei wo die DNHID herkommt gibt es ca. 8 Mio. Sätzen. Ich denke, dass hier irgendwo das Problem liegt.
Dieser Eintrag verursacht den Fehler. Ich habe es ausgesternt und siehe da, es funktioniert super schnell. Weiß der Geier wieso dies interaktiv funktioniert. Hier muss ein Fehler im embedded SQL vorliegen.
Ich werde das SQL von "IN" auf einen join umbauen und sehen was dann passiert.
Die täglichen SQL's, welche funktionieren arbeiten so:
AND DNHID IN (SELECT CDIDNID FROM CDICTLP '+
WHERE CDIBAID = ' + %editc(CDIBAID:'X') +
AND CDISHID = ''' + CdiShId + ''' ' +
AND CDIDISC = ''' + pi@DisC + ''' ' +') '
Da ist die Satzanzahl deutlich geringer.
Klaus