Verwenden der adaptiven Pufferung

JDBC-Treiber herunterladen

Mit der adaptiven Pufferung können Daten mit großen Werten ohne den Aufwand von Servercursorn abgerufen werden. In Anwendungen kann die Funktion der adaptiven Pufferung mit allen Versionen von SQL Server verwendet werden, die vom Treiber unterstützt werden.

Wenn Microsoft JDBC-Treiber für SQL Server eine Abfrage ausführt, ruft der Treiber normalerweise alle Ergebnisse vom Server in einen Anwendungsspeicher ab. Obwohl bei diesem Ansatz die Ressourcenauslastung für SQL Server reduziert wird, kann ein OutOfMemoryError in der JDBC-Anwendung für die Abfragen ausgelöst werden, bei denen sehr große Ergebnisse zurückgegeben werden.

Damit Anwendungen sehr große Ergebnisse behandeln können, stellt Microsoft JDBC-Treiber für SQL Server die adaptive Pufferung bereit. Mithilfe der adaptiven Pufferung ruft der Treiber Ergebnisse der Anweisungsausführung erst dann von SQL Server ab, wenn sie in der Anwendung benötigt werden, statt alle Ergebnisse auf einmal abzurufen. Der Treiber verwirft außerdem die Ergebnisse, sobald die Anwendung nicht mehr auf sie zugreifen kann. Im Folgenden werden einige Szenarien beschrieben, in denen die Verwendung der adaptiven Pufferung sinnvoll sein kann:

  • Die Abfrage liefert ein sehr umfangreiches Resultset: Die Anwendung kann eine SELECT-Anweisung ausführen, die mehr Zeilen zurückgibt, als im Speicher der Anwendung gespeichert werden können. In vorherigen Releases musste die Anwendung einen Servercursor verwenden, um einen OutOfMemoryError zu vermeiden. Die adaptive Pufferung ermöglicht es, einen schreibgeschützten Vorwärtsdurchlauf durch eine beliebig große Ergebnismenge durchzuführen, ohne einen Servercursor zu benötigen.

  • Die Abfrage erzeugt sehr umfangreicheSQLServerResultSet-Spalten oderSQLServerCallableStatement-OUT-Parameterwerte: Die Anwendung kann einen einzelnen Wert (Spalte oder OUT-Parameter) abrufen, der zu groß ist, um vollständig im Anwendungsspeicher gespeichert zu werden. Durch die adaptive Pufferung kann die Clientanwendung solche Werte mithilfe der Methoden getAsciiStream, getBinaryStream oder getCharacterStream als Datenstrom abrufen. Die Anwendung ruft den Wert aus dem SQL Server ab, während sie aus dem Datenstrom liest.

Hinweis

Mit adaptiver Pufferung puffert der JDBC-Treiber nur die benötigte Datenmenge. Der Treiber stellt keine öffentliche Methode zum Steuern oder Beschränken der Puffergröße bereit.

Festlegen der adaptiven Pufferung

Ab Version 2.0 des JDBC-Treibers ist das Standardverhalten des Treibers adaptiv. Mit anderen Worten: Um das adaptive Pufferungsverhalten zu erhalten, muss Ihre Anwendung dieses Verhalten nicht explizit anfordern. In Release 1.2 lautete der Puffermodus jedoch standardmäßig vollständig, und die Anwendung musste den Modus für die adaptive Pufferung explizit anfordern.

Es gibt drei Möglichkeiten, mit denen eine Anwendung die Verwendung der adaptiven Pufferung für die Anweisungsausführung anfordern kann:

Bei Verwendung der JDBC-Treiberversion 1.2 mussten Anwendungen das Anweisungsobjekt in die Klasse SQLServerStatement umwandeln, um die Methode setResponseBuffering zu verwenden. Die Codebeispiele in den Artikeln Beispiel zum Lesen umfangreicher Daten und Beispiel zum Lesen umfangreicher Daten mit gespeicherten Prozeduren veranschaulichen diese alte Verwendung.

Mit Version 2.0 des JDBC-Treibers können Anwendungen jedoch die isWrapperFor-Methode und die unwrap-Methode verwenden, um auf die herstellerspezifischen Funktionen zuzugreifen, ohne Vermutungen über die Klassenhierarchie der Implementierung anstellen zu müssen. Einen Beispielcode finden Sie in dem Thema Beispiel zum Aktualisieren umfangreicher Daten.

Abrufen umfangreicher Daten mit adaptiver Pufferung

Wenn große Werte einmal mithilfe der get<Typ>Stream-Methoden gelesen werden und auf die ResultSet-Spalten und die CallableStatement-OUT-Parameter in der Reihenfolge zugegriffen wird, in der sie von SQL Server zurückgegeben werden, wird die Auslastung des Anwendungsspeichers bei der Verarbeitung der Ergebnisse durch die adaptive Pufferung minimiert. Beim Verwenden der adaptiven Pufferung:

  • Die in den Klassen SQLServerResultSet und SQLServerCallableStatement definierten get<Type>Stream-Methoden geben standardmäßig nur einmal lesbare Streams zurück, obwohl die Streams zurückgesetzt werden können, wenn sie von der Anwendung markiert wurden. Wenn die Anwendung den Datenstrom reset möchte, muss sie zunächst die Methode mark für diesen Datenstrom aufrufen.

  • Die in den Klassen SQLServerClob und SQLServerBlob definierten Methoden get<Type>Stream geben Streams zurück, die immer wieder an den Anfang des Streams gesetzt werden können, ohne die mark-Methode aufzurufen.

Wenn die Anwendung adaptive Pufferung verwendet, können die von den get<Typ>Stream-Methoden abgerufenen Werte nur einmal abgerufen werden. Wenn Sie versuchen, eine get<Typ>-Methode für die gleiche Spalte oder den gleichen Parameter aufzurufen, nachdem die get<Typ>Stream-Methode des gleichen Objekts aufgerufen wurde, wird eine Ausnahme mit der folgenden Meldung ausgelöst: „Auf die Daten wurde zugegriffen; sie sind für diese Spalte oder diesen Parameter nicht verfügbar.“

Hinweis

Beim Abrufen von ResultSet.close() während der Verarbeitung eines Resultsets muss der Microsoft JDBC-Treiber für SQL Server alle verbleibenden Pakete lesen und verwerfen. Dies kann erhebliche Zeit in Anspruch nehmen, wenn die Abfrage ein großes Dataset zurückgegeben hat, insbesondere dann, wenn die Netzwerkverbindung langsam ist.

Richtlinien für die Verwendung der adaptiven Pufferung

Entwickler sollten sich an diese wichtigen Richtlinien halten, um die Speicherauslastung durch die Anwendung zu minimieren:

  • Vermeiden Sie die Verwendung der Verbindungszeichenfolgeneigenschaft selectMethod=cursor, damit die Anwendung ein sehr großes Resultset verarbeiten kann. Die Funktion der adaptiven Pufferung ermöglicht Anwendungen, sehr große, schreibgeschützte Resultatmengen, die nur vorwärts gelesen werden können, zu verarbeiten, ohne einen Servercursor zu verwenden. Beachten Sie, dass, wenn Sie selectMethod=cursor festlegen, alle nur vorwärtsgerichteten, schreibgeschützten Ergebnismengen betroffen sind, die von dieser Verbindung erzeugt werden. Mit anderen Worten: Wenn Ihre Anwendung regelmäßig kurze Resultsets mit nur wenigen Zeilen verarbeitet, verbraucht das Erstellen, Lesen und Schließen eines Servercursors für jedes Resultset sowohl clientseitig als auch serverseitig mehr Ressourcen als in dem Fall, dass selectMethod nicht auf cursor festgelegt ist.

  • Lesen Sie große Text- oder Binärwerte als Datenströme, indem Sie die Methoden getAsciiStream, getBinaryStream oder getCharacterStream anstelle der getBlob- oder getClob-Methode verwenden. Ab Release 1.2 stellt die SQLServerCallableStatement-Klasse neue get<Typ>Stream-Methoden hierfür bereit.

  • Stellen Sie sicher, dass Spalten mit potenziell großen Werten in der Liste der Spalten in einer SELECT-Anweisung am Ende platziert werden und dass die get<Typ>Stream-Methoden von SQLServerResultSet verwendet werden, um in der Reihenfolge auf die Spalten zuzugreifen, in der sie ausgewählt werden.

  • Stellen Sie sicher, dass OUT-Parameter mit potenziell großen Werten in der Liste der Parameter im SQL zum Erstellen von SQLServerCallableStatement zuletzt deklariert werden. Stellen Sie außerdem sicher, dass die get<Typ>Stream-Methoden von SQLServerCallableStatement verwendet werden, um auf die OUT-Parameter in der Reihenfolge zuzugreifen, in der sie deklariert wurden.

  • Vermeiden Sie, mehrere Anweisungen gleichzeitig über dieselbe Verbindung auszuführen. Das Ausführen einer weiteren Anweisung vor dem Verarbeiten der Ergebnisse der vorhergehenden Anweisung kann dazu führen, dass nicht verarbeitete Ergebnisse im Anwendungsspeicher gepuffert werden.

  • Es gibt einige Fälle, in denen die Verwendung von selectMethod=cursor anstelle von responseBuffering=adaptive vorteilhafter wäre, z. B.:

    • Wenn Ihre Anwendung eine schreibgeschützte, nur vorwärtsgerichtete Ergebnismenge langsam verarbeitet, etwa wenn jede Zeile erst nach einer Benutzereingabe gelesen wird, kann die Verwendung von selectMethod=cursor anstelle von responseBuffering=adaptive dazu beitragen, die Ressourcennutzung von SQL Server zu verringern.

    • Wenn Ihre Anwendung zwei oder mehr schreibgeschützte Resultsets, die nur vorwärts gelesen werden können, gleichzeitig über dieselbe Verbindung verarbeitet, kann die Verwendung von selectMethod=cursor anstelle von responseBuffering=adaptive dazu beitragen, den Speicherbedarf des Treibers bei der Verarbeitung dieser Resultsets zu verringern.

    In beiden Fällen müssen Sie den zusätzlichen Aufwand des Erstellens, Lesens und Schließens der Servercursor berücksichtigen.

Darüber hinaus bietet die folgende Liste einige Empfehlungen für blätterbare und ausschließlich vorwärtsgerichtete, aktualisierbare Ergebnismengen:

  • Bei scrollfähigen Resultsets liest der Treiber beim Abrufen eines Zeilenblocks immer die von der getFetchSize-Methode des SQLServerResultSet-Objekts angegebene Anzahl von Zeilen in den Speicher ein, auch bei aktivierter adaptiver Pufferung. Wenn das Scrolling einen OutOfMemoryError verursacht, können Sie die Anzahl der abgerufenen Zeilen verringern, indem Sie die setFetchSize-Methode des SQLServerResultSet-Objekts aufrufen, um die Abrufgröße auf eine kleinere Zeilenanzahl festzulegen und ggf. sogar auf eine Zeile verringern. Wenn sich dadurch ein OutOfMemoryError nicht vermeiden lässt, verzichten Sie darauf, sehr große Spalten in scrollbare Ergebnismengen aufzunehmen.

  • Bei nur vorwärts durchlaufbaren aktualisierbaren Ergebnismengen liest der Treiber beim Abrufen eines Zeilenblocks normalerweise die von der Methode getFetchSize des Objekts SQLServerResultSet angegebene Anzahl von Zeilen in den Speicher, selbst wenn für die Verbindung adaptives Puffern aktiviert ist. Wenn das Aufrufen der next-Methode des SQLServerResultSet-Objekts einen OutOfMemoryError verursacht, können Sie die Anzahl der abgerufenen Zeilen verringern, indem Sie die setFetchSize-Methode des SQLServerResultSet-Objekts aufrufen, um die Abrufgröße auf eine kleinere Zeilenanzahl festzulegen und ggf. sogar auf eine Zeile verringern. Sie können auch erzwingen, dass der Treiber keine Zeilen puffert, indem Sie vor dem Ausführen der Anweisung die setResponseBuffering-Methode des SQLServerStatement-Objekts mit dem Parameter adaptiv aufrufen. Da die Ergebnismenge nicht scrollfähig ist, verwirft der Treiber einen großen Spaltenwert, wenn die Anwendung mithilfe einer der get<Type>Stream-Methoden darauf zugreift, sobald die Anwendung ihn liest, genau wie bei den vorwärtsgerichteten, schreibgeschützten Ergebnismengen.