2017-02-21 1 views
5

Ich habe einen Code wie folgt unten,resultSet.next(): Ruft es Daten aus dem Puffer ODER aus der Datenbank ab?

try (Connection connection = this.getDataSource().getConnection(); 
     PreparedStatement statement = connection.prepareStatement(sqlQuery);) { 


     try { 
      statement.setFetchSize(10000); // Set fetch size 
      resultSet = statement.executeQuery(); 

      while (true) { 
       resultSet.setFetchSize(10000); 
       boolean more = resultSet.next(); 
       if (! more) { 
        break; 
       } 
       // populating an arraylist from the value from resultSet 
      } 
     } 
     catch (Exception e) { 
      LOGGER.error("Exception : "+e); 
     } 
    } catch (SQLException e) { 
     LOGGER.error("Exception : "+e); 
    } 

Mein Verständnis ist, wie folgt,

Die Aussage Fetch-Größe ist 10000. wenn statement.executeQuery() ausgeführt wird, gibt sie den ResultSet Cursor. Es wird 10000 Zeilen im Speicher haben. Wenn resultSet.next aufgerufen wird, wird eine Zeile aus dem Speicherpuffer abgerufen. (eine Zeile pro Anruf). Wenn keine weiteren Zeilen im Speicher vorhanden sind, wird die Abfrage erneut ausgelöst, und 10000 Zeilen werden erneut aus der Datenbank abgerufen und im Puffer gespeichert. Dies setzt sich fort, bis es keine Zeilen ist also von DB

geholt werden, wenn mein Verständnis richtig ist, wie viele tatsächliche DB nennt für insgesamt Reihen von 210.000 dort sein? Ist es 21? (210000/10000)

Auch wenn und wer die DB aufruft (wenn Zeilen im Puffer alle gelesen werden), um mehr Zeilen zu bekommen (10000, in meinem Fall) und im Puffer zu speichern. Wann wird der Puffer gelöscht?

Bitte korrigieren Sie mich, wenn ich falsch in meinem Verständnis bin.

Ich muss mit Millionen von Daten in Oracle Database arbeiten.

Vielen Dank für jede Zeiger/Infos

Grüße,

SD

+0

Die 'setFetchSize #' Methode soll ein Hinweis sein. Es hängt vollständig vom JDBC-Treiber ab, ob es verwendet oder ignoriert wird. Auch wer die DB anruft - der Fahrer macht das. Habe das meiste davon [SO Q/A] (http://stackoverflow.com/questions/1318354/what-does-statement-setfetchsizensize-method-really-do-in-sql-server-jdbc-driv) –

+0

Im Falle des OCI-Treibers gibt es einen Abschnitt in der Dokumentation, der die Anzahl der Netzwerk-Round-Trips pro OCI-Aufruf beschreibt. Der JDBC-Treiber ist nicht auf diese Weise dokumentiert - er bietet API auf höherer Ebene. Sie können das OCI-Dokument jedoch als Einführung in das Thema verwenden. – ibre5041

Antwort

3

Die einzigen Menschen, die auf Ihre Frage antworten können, sind die Autoren des Treibers Oracle JDBC.

Das besagt, dass ein Aufruf von db, um den nächsten Datenblock zu lesen, nicht mehr als ein paar Millisekunden (oder weniger) dauern wird. Der Großteil der Zeit hängt von der Übertragungsrate und möglicherweise davon ab, wie Sie Daten erhalten aus der Ergebnismenge.

Ich denke, sobald Sie über ein paar hundert Rekord pro Anruf gehen Sie in abnehmende Rendite Einstellung einer größeren Abrufgröße.

Zum Löschen des Puffers ist dies meist die Garbage Collection-Domäne, sobald Sie den Verweis auf das Resultset verlieren.

Stellen Sie sicher, dass Ihre Anweisung FORWARD ONLY ist, sowohl aus Gründen der Leistung als auch des Speicherbedarfs.

connection.createStatement(ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY);

+0

nützlicher Link: [Oracle JDBC-Dokumentation] (https://docs.oracle.com/cd/E11882_01/java.12/e16548/resltset.htm#JJDBC28621) – Izruo

+0

Eine Abrufgröße von> 1K macht wahrscheinlich keinen großen Unterschied . Wenn Sie sehen möchten, was von der Datenbank aus vorgeht, können Sie SQL Tracing aktivieren – BobC

4

Sorry, aber Ihr Verständnis ist falsch. Es gibt keine "Abfrage wird erneut ausgelöst".

Die Ausführung der Abfrage erfolgt einmalig. Dies dauert eine gewisse Zeit für die Verarbeitung der Abfrage (zu der Sie nur die Abfrage optimieren können) und dann werden auf dem Server Zeilen erstellt, die an den Client übertragen werden müssen. Während die Zeilen übertragen werden, generiert der Server wahrscheinlich weiterhin mehr zu übertragende Zeilen und puffert diese auf dem Server. Diese serverseitige Pufferung steht in keinem Zusammenhang mit der Art der Pufferung, über die wir in diesem Artikel sprechen, und Sie haben sehr wenig Kontrolle darüber. (Vielleicht mittels Server-Konfiguration, wenn überhaupt.) Irgendwann wurden alle Zeilen auf dem Server gesammelt, und dann bleibt nur übrig, die verbleibenden Zeilen vom Server zum Client zu übertragen.

Also, so weit der Client sagen kann, gibt es eine gewisse Verzögerung, wenn der Server die Abfrage an den Server gesendet hat, nachdem der Server darüber nachdenkt, nach denen Zeilen mit einer Rate verfügbar sind, die normalerweise wie lautet so schnell wie der Draht sie tragen kann. Also beginnt der Client diese Zeilen mit resultSet.next() zu lesen.

Ohne jede Pufferung, jeder Anruf an resultSet.next() würde eine Anfrage vom Client an den Server senden, ihm sagen, die nächste Zeile zu senden, und der Server würde nur mit dieser Zeile antworten. Das würde die erste Zeile sehr schnell ergeben, aber auf lange Sicht wäre es sehr ineffizient, weil es zu viele Rundreisen zwischen dem Client und dem Server verursachen würde.

Mit der Pufferung wird der erste Aufruf an resultSet.next() eine Reihe von Zeilen vom Server anfordern. Dadurch wird die Zeit für den Empfang der ersten Zeile erhöht, da Sie warten müssen, bis 100 Zeilen über die Verbindung gesendet werden. Auf lange Sicht wird jedoch der Gesamt-Netzwerk-Overhead erheblich reduziert, da dies nur der Fall ist ein Hin- und Rückweg zwischen dem Client und dem Server pro Bündel.

Die ideale Strategie für resultSet.setFetchSize() ist, es so zu lassen wie es ist und sich nicht zu viele Sorgen machen.

Aber wenn Sie über Leistung paranoid sind, dann wäre eine gute Strategie, mit einer ziemlich kleinen Abrufgröße zu beginnen (sagen wir 10), um Ihre erste Zeile schnell zu bekommen und dann weiter zu verdoppeln, bis sie a erreicht bestimmtes Maximum (sagen wir 100), jenseits dessen es wirklich keine Verbesserung gibt.

+0

Ihr letzter Absatz scheint darauf hinzudeuten, dass wir die Abrufgröße für ein offenes ResultSet während der Verarbeitung ändern können. Ist es das, was du meintest? –

+0

@GordThompson Nun, das habe ich gemeint. Ich nehme an, es funktioniert, weil es nicht versagt, wenn das OP es verwendet. Ich kann natürlich falsch liegen. Ich würde annehmen, dass es von der RDBMS-Implementierung abhängt, aber ich habe den Standard nicht betrachtet. Aber etwas sagt mir, dass deine Frage rhetorisch ist. Warum sagst du nicht einfach, was du weißt, damit ich den letzten Absatz korrigieren kann? –

+0

@GordThompson Das Ändern der Abrufgröße für einen geöffneten Cursor ist zulässig. Ob der JDBC-Treiber dies unterstützt oder nicht, wird durch die Implementierung definiert. –

Verwandte Themen