2010-10-08 12 views
6

Ich habe nach einer sehr langsamen SQL-Abfrage gesucht (die aus einer Java-App stammt, die Hibernate in JBoss 5.1 verwendet). Diese bestimmte Abfrage gab ungefähr 10K-Datensätze zurück, benötigte jedoch immer noch 40s oder mehr.Jede Lösung für Oracle TNS Ineffizienzen (viele Roundtrips, Latenz) von einer Java App?

Ich landete schnüffeln den Verkehr mit der Datenbank (wireshark hat einen Dissektor für TNS) und etwas unerwartetes gefunden. Wenn Daten vom Server kamen, befand sich jede Ergebniszeile in einem eigenen TNS-Paket. Außerdem wurde jedes TNS-Paket vom Client (d. H. Dem Anwendungsserver) bestätigt, bevor der nächste von der Datenbank gesendet wurde. Für 10K-Datensätze gibt es 10K-Roundtrips, um ein Paket zu erhalten und es zu bestätigen. Der Einfluss auf die Leistung ist enorm.

Das ist furchtbar ineffizient. TCP erlaubt größere Pakete und hat eine Reihe von Mechanismen (gleitende Fenster, verzögerte ACKs), um die Latenz zu reduzieren und den Durchsatz zu erhöhen. In diesem Fall ist es jedoch das TNS-Protokoll, das seine eigene Verhandlung hinzufügt.

Wenn ich dieselbe Abfrage vom Oracle SQL Developer ausführen, sehe ich dieses Muster nicht. Die Abfrage wird in etwa 1/10 der Zeit abgeschlossen, ohne Tausende von Rundreisen.

Kurzversion: Oracle-Drahtprotokoll (TNS) scheint Daten in einem TNS-Paket pro Abfrageergebniszeile zu übergeben und erfordert, dass jedes Paket vom Client bestätigt wird, bevor der Server den nächsten sendet.

Ich habe einige Informationen dazu [hier] [1] gefunden (scrollen Sie nach unten bis zum Abschnitt 'Die SDU und TDU Parameter in der tnsnames.ora Datei').

Und damit meine Frage: ist es möglich, das Verhalten des Oracle-Treibers zu steuern (ich verwende 10.2.0.4.0), so dass das TNS-Protokoll effizienter ist? Auch dies ist eine ziemlich normale J2EE-App, die in JBoss eingesetzt wird.

Vielen Dank!

+0

Hey, danke für eingehende Frage mit ein paar Tipps für Leute mit ähnlichen Situationen .. Upgesprochen .. – TonyP

Antwort

6

Tune die SDU und TDU Parameter in tnsnames.ora und listener.ora

So stellen Sie die Chargengröße zu starten auf 100 für die aktuelle Anweisung.

((OracleStatement)stmt).setRowPrefetch (100); 

Hinweis:

die PREFETCHSIZE einstellen kann die Leistung einer Anwendung beeinflussen. Erhöhen Sie die Vorabrufgröße reduzieren Sie die Anzahl der Round-Trips erforderlich, um alle Daten zu erhalten, aber wird Speicherauslastung erhöhen. Dies wird hängen von der Anzahl und Größe der Spalten in der Abfrage und die Anzahl der Zeilen voraussichtlich zurückgegeben werden. Es wird auch auf den Speicher und CPU laden der JDBC-Client-Maschine abhängen. Das Optimum für einen eigenständigen Client Anwendung unterscheidet sich von einem stark ausgelasteten Anwendungsserver .Die Geschwindigkeit und Latenz des Netzwerks Verbindung sollte auch sollte consideredconnection auch

(von Oracle Database JDBC Developer's Guide and Reference)

Verfügbare Verbindungseigenschaften here berücksichtigt werden.

Schauen Sie sich auch Oracle UCP an.

+0

Danke, nach dem googlen des Zeilenvorabrufs habe ich Folgendes gefunden: "Standard JDBC erhält das Ergebnissatz eine Zeile nach dem anderen, und jede Zeile benötigt einen Hin- und Rückflug zur Datenbank" unter http://download.oracle.com/docs/cd/ B19306_01/java.102/b14355/oraperf.htm was erklärt, was ich gesehen habe. Hmm .. ist es möglich, auf der Datenquellenebene zu setzen? Die Liste der Parameter unter http://docs.jboss.org/hibernate/core/3.3/reference/en/html/session-configuration.html enthält keine Einstellungen für den Prefetch. – wishihadabettername

+1

In der Zwischenzeit fand ich eine Treibereigenschaft (defaultRowPrefetch) unter http://download.oracle.com/docs/cd/B19306_01/java.102/b14355/urls.htm#i1006362 – wishihadabettername

+0

Verwenden Sie UCP? http://www.oracle.com/technetwork/database/features/jdbc/index-091264.html – oluies

3

Versuchen Sie, die Abrufgröße für Ihr Objekt zu erhöhen.

Ich denke, die Standard-10 ist, so dass Sie könnten versuchen, mit 100.

 
Statement stmt = connection.createStatement(); 
stmt.setFetchSize(100); 
ResultSet rs = stmt.executeQuery("SELECT ..."); 
+0

Erhöhung der Abrufgröße verbesserte Dinge durch Füllen der TCP-Pakete in der Tat. – wishihadabettername