Performante Zugriffe auf DB2 über JDBC und SQLJ

Werbung
Optimierung der DB2 Performance in JDBC & SQLJ
1 Optimierung der Performance - Übersicht
Wie bereits diskutiert, läuft "static SQL", mit Ausnahme einier weniger Fälle schneller als
"dynamic SQL" in JDBC. Die folgenden Abschnitte beschreiben eine Reihe von Technologien,
die man anwenden sollte, um die Performance von DB2 im Umfeld von SQLJ oder JDBC zu
sichern.
1.1 Ausschalten von AutoCommit
Verwendet man JDBC, um eine Verbindung aufzubauen, so wird das "AutoCommit feature" für
die Datenbank per default eingeschaltet.
AutoCommit, wie der Name schon sagt, "commited" jedes SQL Statement, das an die
Datenbank abgesetzt wurde. Diese automatische Funktion kann den Aufwand an SQL, das zu
kodieren wäre, reduzieren, aber es vermindert auch die gesamte Antwortzeit von DB2, da jedes
Statement bei seiner Ausführung zusätzlichen "overhead" verursacht.
Das "AutoCommit feature" wird aber auch die Integrität der Anwendung positiv beeinflussen und
die Konsistenz der Daten sicherstellen.
Um das AutoCommit für eine Verbindung auszuschalten verwende man folgenden Code zum
Aufbau dieser Verbindung:
con = DriverManager.getConnection(url, userid, password);
con.setAutoCommit(false);
1.2 Begrenzen der zu verarbeitenden "columns"
SQL ist eine übersichtliche und mächtige Sprache. Eine Anweisung wie
SELECT * FROM EMP_ACT
holt alle Daten aus der Tabelle.
Das Statement ist einfach zu formulieren, aber für DB2 hat es folgende Form:
SELECT EMPNO, PROJNO, ACTNO, EMPTIME, EMSTDATE,EMENDATE FROM EMP_ACT
Hier entsteht zusätzlicher "overhead" durch das lesen jeder "column" und der Modifikation der
Query. Z.B. müssen "string values" von Unicode aus Java auf die EBCDIC/ASCII Zeichensets
von DB2 konvertiert werden. Zusätzlich dazu erzeugt Java ein Objekt für jede Spalte, die einen
anderen Datentyp verwendet, als die vorgegebenen "Java primitive character types" wie
VARCHAR s.
Gibt man mehr Spalten an, als man wirklich benötigt, so verschwendet man "resources" und
wird die Performance negativ beeinflussen. Um eine bestmögliche Performance für SQL
Statement zu erzielen, sollte man die zu lesenden Spalten auf ein benötigtes Minimum
reduzieren.
1.3 Nutzung von "online checking"
Mit dem Kommando db2sqljcustomize kann man SQLJ Profile erzeugen.
Dieses Kommando kann aber auch über die -onlinecheck Option ( = YES) angestoßen
werden. Dieses Kommando beinhaltet einen "online checker" für "static SQL". Der "online
checker" durchläuft verschiedene Funktionen, u. a. die Prüfung auf die JDBC/SQLJKompatibilität und Konvertierungsverarbeitung. Er bestimmt die Länge der "string columns" und
kann so die "run-time performance" der Java Applikation verbessern.
Um diese Option nutzen zu können, muss man auf eine DB2 Datenbank verbunden sein,
während man das db2sqljcustomize Kommando verwendet.
1.4 Tuning der "JVM heap size"
Java Programme laufen auf der Java Virtual Machine(JVM). Jede JVM besitzt eine "default
initial heap size" von 1 MB und eine "default maximum heap size" von 8 MB. Man sollte die
"heap size" über die -ms ("starting heap size") und -mx ("maximum heap size") Parameter der
java "command line parameter" setzen.
"heap" wird aus einer Reihe von Performancegründen verwendet. Bei SQLJ oder JDBC wird ein
Java Programm typischerweise damit beenden, dass es eine Menge von Java Objekten erzeugt
und löscht. Diese Objekte sind zum Zugriff und zum Halten der relationalen Daten(objekte)
notwendig. Dazu sei gesagt, dass die "default heap sizes" in der Regel nicht groß genug sind,
um eine adäquate Performance zuzulassen. Eine Erhöhung dieser Werte kann zu einer
besseren "run-time performance" für eine Applikation führen.
Mit einer größeren "heap" hat man mehr Platz für das Erzeugen der Java Objekte. Außerdem
kann das setzen von "minimum" und "maximum heap size" auf denselben wert die Performance
insofern positiv beeinflussen als der Prozess der "reallocation" des Speichers für das "heap"
beschleunigt wird.
Man sollte darauf achten, dass größere "heap sizes" in weniger häufigen "garbage collection"
Aktionen resultieren – "garbage collection" für größere "heaps" dauern länger.
1.5 Verwenden von CACHEDYN
DB2 kann die Resultate eines Prepare eines "dynamic SQL" Statements in einem "cache"Speicher ablegen. Benutzt man JDBC Statements in einer Applikation oder werden in SQLJ
spezielle Operationen, wie "cursor-controlled updates" auf einem Objekt außerhalb des Cursors
ausgeführt, so wird die Applikation "dynamic SQL" ausführen.
DB2 kann "dynamic SQL" Statements nur im Cache ablegen, wenn der Parameter
CACHEDYN=YES in den Subsystemparametern gesetzt ist.
Der Einsatz von "Statement caching" kann die Kosten von "dynamic SQL" näher an die Kosten
des "static SQL" Verfahrens bringen.
2 Vermeiden allgemeiner Fehler
2.1 "Connection contexts"
In diesem Kapitel werden einige der am weitesten verbreiteten Fehler, die die Performance von
DB2 in Zusammenhang mit Java Applikationen beeinflussen, dargestellt.
Wie bereits erwähnt, hat der SQLJ Code, der hier gezeigt wird einen "context parameter" nach
der SQLJ Anweisung:
#sql [context] {SELECT EMPNO INTO :strEmpNo FROM EMP_ACT WHERE PROJNO
=:strProjNo};
Was ist der Sinn dieses optionalen "context Parameters"?
Der "context" eines SQL Statements definiert die Besonderheiten einer "connection", die zum
Zugriff auf die Datenbank gewünscht werden; z.B. "user name" und Zieldatenbank. Man kann
also mehr als einen "context" in einer Applikation angeben.
"Multiple contexts" betreffen beispielsweise unterschiedliche Benutzer – "uncommitted"
Modifikationen, die für einen bestimmten "context" gedacht sind, sind für andere "contexts" nicht
sichtbar und ein "rollback" oder "commit" für einen bestimmten "context" gilt ebenfalls nicht für
andere "contexts" usw.
Obwohl dieser Parameter optional ist, existiert mindestens ein "context" für jede "connection".
Spezifiziert man den "context" für ein SQL Statement nicht selbst, so nutzt die Applikation einen
"default context".
Man muss also darauf achten, dass dies nicht ungewollt geschieht, nur weil man vergessen hat,
dass jede Verbindung einen "context" zusammen mit dem jeweiligen SQL Statement mitliefert.
Man sollte also möglichst keine "multiple contexts" zusammen mit JVM und den zugehörigen
"database resources" nutzen. Sie könnten auch in einem "deadlock" zwischen zwei "connection
contexts" derselben Applikation enden.
2.2 Der Nutzen von "DefaultContext"
Eine Methode, einen ungeeigneten "default context" anzuwenden, ist die Definition eines
eigenen DefaultContext Objekts in einer Applikation:
DefaultContext ctx = DefaultContext.getDefaultContext();
if (ctx == null)
{
// Aufbau des URL (sample ist der Name der DB)
String url = "jdbc:db2://localhost:50000/SAMPLE";
// verbinden mit der 'sample' Database mit user ID und password
con = DriverManager.getConnection(url, "myusername", "mypassword");
con.setAutoCommit(false);
ctx = new DefaultContext(con);
DefaultContext.setDefaultContext(ctx);
}
...
Dieser Code prüft das Vorhandensein eines "default context" und weist dann die neu erstellte
"connection" dem lokalen DefaultContext Objekt zu.
2.3 "Cleaning up"
Keine Aufgabe ist erledigt bis der "cleanup"-Prozess beendet ist. Diese Maxime gilt auch für
Java Code.
Greift man auf DB2 zu werden eine Reihe unterschiedlicher Objekte genutzt. Nutzt man nun
JDBC zum Datenzugriff, werden ResultSets erzeugt, die die Ergebnisse der Query
enthalten. Man kann auch PreparedStatement und CallableStatement Objekte
erzeugen, um SQL auszuführen. Man benutzt SQLJ Iteratoren, um "multiple rows" einer
zurückgegebenen Datenmenge zu verarbeiten.
Jedes dieser Objekte verwendet bestimmte Ressourcen sowohl im Speicher, als auch in JDBC.
Man muss darauf achten, diese explizit wieder ferizugeben ("close") wenn man mit seiner Arbeit
fertig ist und diese nicht mehr benötigt. Werden beispielsweise ResultSets nicht geschlossen,
riskiert man einen Engpass in diesen Ressourcen. Der benutzte "database cursor" wird solange
verwaltet bis das zugehörige PreparedStatement geschlossen wird.
CallableStatements geben ihre "holds" in den "call sections" nicht frei bis sie
geschlossen werden. Alle diese Objekte werden geschlossen wenn ihre zugehörige
"connection" zur Datenbank geschlossen wird. Dennoch, das explizite Schließen dieser Objekte
allein stellt nicht sicher, dass keine unnötigen Ressourcen mehr mitverwaltet werden. Die
Vorgehensweise ist aber jedenfalls die bessere Programmiertechnik.
Für SQLJ gilt, man kann einfach die close() Methode auf den "connection context"
anwenden, um sowohl "context" als auch die unterliegende JDBC "connection" zu schließen. In
JDBC aber kann man nicht einfach die unterliegende "connection", die mit der
getConnection() Methode für den "context" zurückgeliefert wurde schließen: Man muss hier
beides schließen – die "connection" und die "context objects".
Herunterladen