PDA

View Full Version : SQL zu langsam?



Seiten : 1 [2] 3

Fuerchau
28-03-06, 07:33
Es ist ja immer so schön einfach, die verfügbaren Funktionen zu nutzen ohne sich Gedanken über die Wirkung zu machen.
Insert/Updates auf Recordset-Ebene sind immer die langsamsten die es gibt.
Man beachte, was der Treiber bzw. die SQL-Schicht leisten muss, bevor es überhaupt zur Aktion kommt.

Ein Insert/Update wird vom Treiber intern erst zusammengebaut, prepared, ausgeführt und das Statement wieder freigegeben.
Wenn ich einen Recordset.Update() bzw. Recordset.Insert() kodiere ist also einiges zu tun.
Wobei ich mich beim Update frage, wo der Schlüsselbezug herkommt oder der korrekte Satz automatisch ermittelt wird.

Im Gegenzug ist ein selbstgestricktes Prepared-Statement um Faktoren schneller.
Also ein "insert into myfile (f1, f2, ...) values(?, ?, ...)" bzw. ein "update myfile set f1=?, f2=?,... where Key=?" mit der entsprechenden Execute-Methode.

holgerscherer
28-03-06, 20:23
Ein Insert/Update wird vom Treiber intern erst zusammengebaut, prepared, ausgeführt und das Statement wieder freigegeben.

Wenn ich mir so die CPU-Auslastung anschaue (20% DB-Kapazität), dann befürchte ich dass die AS400 eigentlich nur mit dem auseinanderfriemeln der SQL-Statements beschäftigt ist. (Aus dem Grund geht IBM beim POWER6 berechtigterweise Richtung Takt, nicht Richtung I/O).

Die Platten und das RAM sinds in dem Falle nicht, die Werte sind hier banal (@Dieter: das kriegen selbst zwei 35er Festscheiben noch geregelt). Da ich mich nicht JAVA-Äggsberde schimpfe: Wie siehts denn mit der Zusammenfassung der Insert-Statements aus? Für jeden Satz ein eigenes INSERT INTO ist ja auch nicht wirklich optimal.

Habe neulich ähnliches mit einer (zufällig in der Ecke rumstehenden) 150er gemacht. Mit (per Hand) vorbereiteten INSERTS mit mehreren Sätzen geht die erstaunlich gut ab, dafür, dass ein schwerer Ficus drauf steht...

-h
(jaja, eine 150er als Blumenvasenständer ist zumindest aus physikalischer Betrachtung gewagt)

Fuerchau
31-03-06, 07:37
Wie immer: die Methode ist entscheidend !

"insert into myfile (f1, f2, ...) values(W1, W2, ...)" führt auf jeden Fall zu folgender Aktion:
- Syntax-Check
- Prepare
- Execute
- drop Statement
- ODP's erkennt die AS/400 ggf. automatisch
Wenn ich dann ggf. auch noch jedesmal einen Connect-/Disconnect betreibe, wird auch jedesmal der Job verbunden/getrennt. Die Nutzung eines ODP's entfällt damit.

Seit V5R3 macht die AS/400 folgendes:
- Syntax-Check
- entfernen der Werte ersetzen mit "?"
- prüfen im SQLPKG, ob's das Statement schon mal gab
- a) Wiederverwendung
- b) Prepare
- Einfügen der Werte zum "?"
- Execute

Erheblich beschleunigen kann ich den Vorgang durch ein von mir vorher selbst vorbereitetes Statement:
"Insert into myfile (F1, F2, ...) value(?, ?, ...)"
- Prepare-Funktion aufrufen
- Parameter setzen
- Execute-Methode

Die AS/400 führt dann die Statements durch die Wiederverwendung direkt aus.
Der Syntax-Check entfällt (bzw. nur noch 1 Mal), das Statement bleibt im aktiven Job auch aktiv und muss nicht neu generiert werden (Resourcen).

Auch wenn das Connection-Pooling für Internet-Anwendungen sehr schön ist, sollte ich vom Design gut überlegen wann ich denn die Verbindung freigebe.
Habe ich vor, mehrere Daten zu schreiben, sollte ich die Verbindung erst trennen, wenn alle Vorgänge abgeschlossen sind.

Insbesonders wenn man doch mal mit Journalisierung und Transaktionen umgeht, verbietet sich das sowieso.
Ich sehe da auch keinen Unterschied zwischen JDBC oder ODBC/OLEDB, da AS/400-seitig immer der selbe Dienst verwendet wird. Auch für DRDA gilt das Gleiche, ausser das der Eingang ein anderer ist.

Bei SQL mit der AS/400 sollte man sich immer entsprechende Gedanken machen, da die Treiberseite meist PC-Optimiert ist und auf MS-Access/SQL-Server konzipiert wurde.
Dies betrifft insbesonders Update/Insert-Cursor auf Recordsets, die meistens von der AS/400 so nicht unterstützt werden.

RobertPic
31-03-06, 13:32
...
Seit V5R3 macht die AS/400 folgendes:
- Syntax-Check
- entfernen der Werte ersetzen mit "?"
- prüfen im SQLPKG, ob's das Statement schon mal gab
- a) Wiederverwendung
- b) Prepare
- Einfügen der Werte zum "?"
- Execute
...


Hallo Fuerchau, sehr gute Erklärung. Da ich noch kein V5R3 habe, ein Frage:

Meiner Meinung nach, kann man diese Funktionalität auch schon bei V5R2 zuschalten.

bei ODBC: Extended Dynamic Support im ODBC-Treiber
bei JDBC: "extended dynamic=true" im Connectionstring

Gehe ich hier recht in der Annahme, oder gibt es unter V5R3 was ganz Neues?

Robert P.

BenderD
31-03-06, 13:49
Hallo,

das wurde schon länger probiert, prepared Statements abzuleiten und zu cachen, was da neu gekommen ist, ist ein System weiter Cache, allerdings sind all diese Caches (auch der vom extended package suppport) zweischneidig. Bei schlechter Trefferquote, oder schwacher Implementierung, kostet die Sucherei mehr als alles andere. Bei JDBC gab es Treiberstände (?!) bei denen das katastrophal war; da hat das löschen eines packages manchmal Verbesserungen um mehr als den Faktor 10 gebracht.
Mit der ach so famosen neuen Query Engine braut sich wieder was zusammen, die macht keine temporären Indexe mehr (wird mit jedem V5R3 PTF sichtbarer), sondern macht dann halt full Table scans, mit steil ansteigendem Ressourcen Verbrauch.

mfg

Dieter Bender

@Baldur: zu den Inserts habe ich Einwände, die verwenden keinen ODP.


Hallo Fuerchau, sehr gute Erklärung. Da ich noch kein V5R3 habe, ein Frage:

Meiner Meinung nach, kann man diese Funktionalität auch schon bei V5R2 zuschalten.

bei ODBC: Extended Dynamic Support im ODBC-Treiber
bei JDBC: "extended dynamic=true" im Connectionstring

Gehe ich hier recht in der Annahme, oder gibt es unter V5R3 was ganz Neues?

Robert P.

Fuerchau
31-03-06, 14:24
@Dieter
Da muss ich zumindest bei der Verwendung per ODBC wiedersprechen.
Die Datei, in die ich per Insert schreibe ist mit Status "O" eröffnet.
Also auch hier ist die Verwendung von Prepared-Statements aus Performancegründen durchaus sinnvoll.

Da ich nicht weiß, in wie weit der Java-Treiber benannte SQLPKG's unterstützt kann es da durchaus Unterschiede geben.

Um dem Problem der SQLPKG's aus dem Weg zu gehen, kann man mindestens beim ODBC-Treiber sein Paket in die QTEMP legen. Mit dem IBMDA400 gehts ab V5R3 auch.
Meine Erfahrungen mit dieser Methode sind durchaus sehr gut.

Was den Optimizer angeht teile ich deine Meinung.
Häufig genug wird ein Zugriffsweg vorgeschlagen der anschließend keine Verwendung findet, da der Optimizer den Tablescan immer noch für optimaler hält.
Das ist aber doch eher selten der Fall.

Da ich inzwischen doch einiges mit ODBC getestet habe, konnte ich mittels DEBUG-Modus die meisten SQL's wie gewünscht beschleunigen.

Ach ja, es gibt da noch einen kleinen Engpass:

Mangels Journalisierung werden Anwendungsdateien häufig mit FRCRATIO(1) angelegt.
Dadurch kann es zu erheblichen Einbußen beim Schreiben kommen.
Ein simpler CPYF kann z.B. um mehr als einen Faktor 1000 beschleunigt werden, wenn FRCRATIO(*NONE) gewählt wird.

Wenn Journalisierung gewählt wurde, sollte auf jeden Fall FRCRATIO abgeschaltet werden.

Dadurch kann es natürlich zu erheblichen Unterschieden zwischen DB/400 und MySQL/SQL-Server/Oracle kommen, da diese Datenbanken eben grundsätzlich journalisieren und somit ein direktes physisches schreiben nicht durchgeführt wird.

Manche DB's (z.B. Firebird) erlauben das abschalten des Write-Caches, was gleichbedeutend mit einem geradezu gewaltigem Performanceverlust ist.

BenderD
31-03-06, 15:27
@Baldur

die sind zwar mit O geöffnet, verwenden aber (so stehts zumindest in den Debug Messages) keinen Zugriffspfad (sondern Eingangsfolge). Wegen des lazy close von SQL bleibt die Datei mit und ohne prepare offen.
Package Namen kann man auch beim JDBC Treiber setzen, QTEMP habe ich noch nicht probiert.
Caching ist auch in der Applikation (gerade bei Zugriffen über Netzwerk) das A und O für gute Performance; das sieht man in Java bei Hibernate, der das automatisch macht.

mfg

Dieter


@Dieter
Da muss ich zumindest bei der Verwendung per ODBC wiedersprechen.
Die Datei, in die ich per Insert schreibe ist mit Status "O" eröffnet.
Also auch hier ist die Verwendung von Prepared-Statements aus Performancegründen durchaus sinnvoll.

Da ich nicht weiß, in wie weit der Java-Treiber benannte SQLPKG's unterstützt kann es da durchaus Unterschiede geben.

Um dem Problem der SQLPKG's aus dem Weg zu gehen, kann man mindestens beim ODBC-Treiber sein Paket in die QTEMP legen. Mit dem IBMDA400 gehts ab V5R3 auch.
Meine Erfahrungen mit dieser Methode sind durchaus sehr gut.

Was den Optimizer angeht teile ich deine Meinung.
Häufig genug wird ein Zugriffsweg vorgeschlagen der anschließend keine Verwendung findet, da der Optimizer den Tablescan immer noch für optimaler hält.
Das ist aber doch eher selten der Fall.

Da ich inzwischen doch einiges mit ODBC getestet habe, konnte ich mittels DEBUG-Modus die meisten SQL's wie gewünscht beschleunigen.

Ach ja, es gibt da noch einen kleinen Engpass:

Mangels Journalisierung werden Anwendungsdateien häufig mit FRCRATIO(1) angelegt.
Dadurch kann es zu erheblichen Einbußen beim Schreiben kommen.
Ein simpler CPYF kann z.B. um mehr als einen Faktor 1000

beschleunigt werden, wenn FRCRATIO(*NONE) gewählt wird.

Wenn Journalisierung gewählt wurde, sollte auf jeden Fall FRCRATIO abgeschaltet werden.

Dadurch kann es natürlich zu erheblichen Unterschieden zwischen DB/400 und MySQL/SQL-Server/Oracle kommen, da diese Datenbanken eben grundsätzlich journalisieren und somit ein direktes physisches schreiben nicht durchgeführt wird.

Manche DB's (z.B. Firebird) erlauben das abschalten des Write-Caches, was gleichbedeutend mit einem geradezu gewaltigem Performanceverlust ist.

Fuerchau
31-03-06, 17:58
Ja ok, dann war das ein Missverständnis.
ODP (OpenDataPath) verstehe ich vom Begriff einfach als geöffnete Datei.
Dass beim Insert kein Zugriffsweg notwendig ist ist schon klar.

Das mit der QTEMP habe ich bereits häufig ausprobiert, da ich da vorallem keine Namenskonflikte habe. In der QGPL sieht man ja häufig so Namen die mit MS anfangen und FBA (Access, MS-Query, VBA) aufhören.
Berechtigungsprobleme sind noch das geringste.

Und auf die gespeicherte Zugriffsanalyse kann man bei richtiger vorherigen SQL-Analyse sowieso verzichten.

COS
15-11-06, 10:44
Nur so nebenbei erwähnt: Spaßeshalber mal 'ne MySQL auf einem stinknormalen Bürorechner installiert, der neben der iSeries steht und dort eine entspr. Tabelle erzeugt. Das Einfügen von Sätzen dauert dabei 'ne knappe Millisekunde... Auch wenn das jetzt kein echter Vergleich ist :)

Markus

Deutliche Performance-Steigerungen kann es (bei JDBC-Insert oder -Update) bringen,
wenn man, statt einzeln jedes Statement auszuführen,

...
stmt.execute() bzw stmt.executeUpdate()
...
die Batch-Funktionalitäten von Statement bzw. PreparedStatement benutzt
(natürlich nur da, wo es Sinn macht; zB Massen-Verarbeitung Insert/Update)

...
for () {
notwendige Parameter setzen
stmt.addBatch()
}
.........
con.setAutoCommit(false);
updateCounts = stmt.executeBatch();

...

BenderD
15-11-06, 10:57
... falls der Treiber das überhaupt unterstützt - das war bei dem Toolboxtreiber nicht immer der Fall, was IBM nicht davon abhielt diese Empfehlung abzugeben; überflüssig zu sagen, dass es damit langsamer wurde.

mfg

Dieter Bender


Deutliche Performance-Steigerungen kann es (bei JDBC-Insert oder -Update) bringen,
wenn man, statt einzeln jedes Statement auszuführen,

...
stmt.execute() bzw stmt.executeUpdate()
...
die Batch-Funktionalitäten von Statement bzw. PreparedStatement benutzt
(natürlich nur da, wo es Sinn macht; zB Massen-Verarbeitung Insert/Update)

...
for () {
notwendige Parameter setzen
stmt.addBatch()
}
.........
con.setAutoCommit(false);
updateCounts = stmt.executeBatch();

...