Wie funktioniert ein JDBC-Treiber die setMaxRows-Methode

Nach den JDBC-Spezifikationen soll die Methode Statement.setMaxRows(int maxRows)

Legt die Grenze für die maximale Anzahl von Zeilen fest, die ein ResultSet-object, das von diesem statementsobjekt generiert wird, auf die angegebene Nummer enthalten kann. Wenn die Grenze überschritten wird, werden die überschüssigen Zeilen stillgelegt.

Beim Testen gegen die Begrenzung der Ergebnismenge auf der SQL-Ebene (ROWSET, TOP und LIMIT) scheinen sowohl das JDBC als auch das SQL-Konstrukt sehr gut zu funktionieren.

Auch bei der Auswahl von Millionen von Zeilen scheint das setMaxRows nicht schlimmer zu sein.

Könnte es sein, weil die database Executor einen database-Cursor verwenden könnte, der nur datasätze auf Anforderung maxRows Wenn also der Treiber die maxRows Schwelle erreicht, kann die database angewiesen werden, den Cursor zu schließen?

Auf diese Weise muss die database nicht eine riesige Ergebnismenge auswählen und an den Draht senden, sondern nur auf der Client-Seite verworfen werden.

In PostgreSQL sendet PgJDBC eine Anfrage auf der Protokollebene, die das Äquivalent zum Anhängen einer LIMIT an die Abfrage ist. Also der database-server weiß, zu versuchen, die Menge an Arbeit, die es tut, wo möglich zu minimieren. Es könnte wählen, einen Plan, der teurer wäre, um alle Zeilen zu holen, aber das kann beginnen, einige Zeilen früher zurückzugeben oder eine große All-Zeilen sortieren zu vermeiden, zum Beispiel.

Ich erwarte, dass Client-Treiber für andere Motoren ähnlich sind – legen Sie eine Grenze hinter die Szenen, oder verwenden Sie einen Cursor und lesen, bis sie genug Ergebnisse haben.

Jeder DBMS und Fahrer wird anders sein, so dass eine einzige endgültige Antwort schwer zu finden sein könnte.

Die meisten JDBC-Fahrer holen Zeilen auf Anforderung (basierend auf der maxRows ), so dass normalerweise maxRows sehr effizient sein wird. Sie in der Regel sogar optimieren, um einfach nicht mehr als maxRows zu holen.

Ein ROWS oder TOP könnte dem databaseserver einige zusätzliche Hinweise zur Optimierung der Abfrage geben, so dass die Einstellung von maxRows möglicherweise nicht so effizient ist wie das max in der Abfrage selbst. Das genaue Verhalten ist fahrer- und datenbankabhängig, so dass es schwer ist, Verhaltens- und performancesmerkmale zu verallgemeinern.

Die bemerkenswerte exception ist der MySQL-Treiber (und wahrscheinlich auch MariaDB), der standardmäßig alle Zeilen Integer.MIN_VALUE (es sei denn, die Integer.MIN_VALUE wird auf Integer.MIN_VALUE ) sofort bei der Abfrageausführung.

Als Beispiel in Jaybird (Firebird JDBC-Treiber) wird folgendes durchgeführt (für TYPE_FORWARD_ONLY ):

 public void fetch() throws SQLException { synchronized (syncProvider.getSynchronizationObject()) { checkClosed(); int maxRows = 0; if (this.maxRows != 0) maxRows = this.maxRows - rowNum; int fetchSize = this.fetchSize; if (fetchSize == 0) fetchSize = MAX_FETCH_ROWS; if (maxRows != 0 && fetchSize > maxRows) fetchSize = maxRows; if (!allRowsFetched && (rows.isEmpty() || rows.size() == rowPosition)) { rows.clear(); stmt.fetchRows(fetchSize); rowPosition = 0; } if (rows.size() > rowPosition) { setNextRow(rows.get(rowPosition)); // help the garbage collector rows.set(rowPosition, null); rowPosition++; } else { setNextRow(null); } } } 

Da der server beschließen kann, mehr Zeilen als angefordert zu senden, werden zusätzliche Checks auf next() .

Oracle verwendet Hersteller-Design-Muster. So werden die Zeilen in dem Moment erzeugt, in dem der Client vom Cursor aus in den ResultSet fährt. Es gibt zwei Optimierungsziele: ALL_ROWS und FIRST_ROWS (bzw. FIRST_ROWS (n)). Bei der Verwendung von first_rows Optimierer Ziel Oracle neigt dazu, mehr verschachtelte Loops über hash_joins zu verwenden, und deshalb sollte es die erste Masse der Ergebnisdaten viel schneller zurückgeben. Aber ich bin mir nicht sicher, ob mit der setMaxRows-Methode auch das Optimierungsziel für die Abfrage geändert wird.