Warum dauert die Abfrage in Microsoft SQL Server 2012 Minuten gegenüber JDBC 4.0, aber zweitens in Management Studio?

9

Ich habe es mit einem Leistungsproblem zu tun, während ein relativ großer ResultSet von einem entfernten Microsoft SQL Server 2012 zu einem Java-Client abgerufen wird, der den Microsoft JDBC-Treiber 4.0 verwendet.

Wenn ich die entsprechende Abfrage auf dem Microsoft SQL Server Management Studio des Remote-Servers ausführe, wird ca. 220k Zeilen fast sofort. Wenn ich die gleiche Abfrage vom Client ausstelle, bleibt es stehen. Derselbe Test funktionierte auch auf dem Client mit einer früheren Version der Datenbank, wo nur ca. 400 Zeilen qualifiziert.

Ich habe versucht, dies anzugehen, indem ich ;responseBuffering=adaptive" an die URL angehängt habe, die an DriverManager.getConnection() übergeben wurde. Nachdem die Verbindung hergestellt wurde, sehe ich diese Eigenschaft (neben mehreren anderen) im Ergebnis von connection.getMetaData().getURL() , aber [ connection.getClientInfo(responseBuffering) gibt null zurück, und was noch mehr ist, ist der Client immer noch.

Was könnte hier schief laufen und wie kann ich den Microsoft SQL Server anweisen (nicht nur vorschlagen - programmatisch in Java), dass er Zeilen in kleineren Chunks anstatt alle auf einmal zurückgeben muss oder JDBC-Abfragezeiten um bis zu verbessern einige andere Maßnahmen.

Zwei weitere Beobachtungen, die etwas seltsam erscheinen und vielleicht auf eine andere Ursache hinweisen:

  • Wenn der Client abstürzt, zeigt er immer noch nur eine relativ geringe CPU-Last, anders als ich es von einer schweren Garbage Collection erwarten würde
  • "responseBuffering = adaptive" sollte der normale Standard Inzwischen

UPDATE Ich habe überprüft und festgestellt, dass der Wechsel von PreparedStatement auf Statement die Dinge in meinem Fall nicht verbessert (es kann anscheinend in

Drux 22.10.2014, 06:49
quelle

4 Antworten

3

Die adaptive Pufferung ist eine gute Antwort. Ich würde auch empfehlen, die Optionen SET der Verbindungen über SQL Server Profiler zu überprüfen.

Stellen Sie beim Starten einer Ablaufverfolgung sicher, dass ExistingConnections ausgewählt ist. Vergleichen Sie eine SPID von einer JDBC-Verbindung und einer SSMS-Verbindung. ARITHABORT kommt mir in den Sinn, da ich einen Unterschied in der Leistung zwischen SSMS und JDBC-Treiber gesehen habe. Microsoft erwähnt es hier kurz: Ссылка . Stack Exchange Informationen hier: Ссылка

Bei Oracle habe ich große Auswirkungen gesehen, indem ich mit der Methode setFetchSize für das Objekt Statement / PreparedStatement gespielt habe. Anscheinend unterstützt der SQL Server-Treiber diese Methode nicht. Es gibt jedoch eine interne Methode im Treiber dafür. Siehe Legen Sie einen Standard-Zeilenvorablesezugriff in SQL Server mithilfe von fest JDBC-Treiber für Details.

Was machst du auch in deiner while (rs.next()) Schleife? Versuchen Sie nichts anderes als eine Spalte wie rs.getInt(1) zu lesen. Schau was passiert. Wenn es fliegt, deutet das darauf hin, dass der Flaschenhals in Ihrer früheren Verarbeitung der Ergebnismenge liegt. Wenn es noch langsam ist, muss das Problem in dem Treiber oder der Datenbank sein.

Sie können SQL Server Profiler verwenden, um die Ausführungen über JDBC und über SSMS zu vergleichen. Vergleichen Sie die CPU, Lese-, Schreib-und Dauer. Wenn sie anders sind, dann ist der Ausführungsplan wahrscheinlich anders, was mich auf das Erste, was ich erwähnt habe, zurückführt: die Optionen SET .

    
Brandon 24.10.2014, 18:17
quelle
2

Ich werde diesen Vorschlag einfach wegwerfen und es Ihnen überlassen, ihn zu testen.

Der JDBC-Treiber kann ALLE Zeilen, bevor er zurückkehrt, wahrscheinlich abholen, während das andere System einfach den offenen Cursor zurückgibt.

Ich habe dieses Verhalten in anderen Datenbanken mit JDBC gesehen, hatte aber keine direkte Erfahrung mit SQL Server.

In den Beispielen, in denen ich es gesehen habe, verhindert das Setzen des automatischen Commits auf "false" für die Verbindung, dass die gesamte Ergebnismenge geladen wird. Es gibt andere Einstellungen, um nur Teile usw. laden zu lassen.

Aber das könnte das grundlegende Problem sein, dem Sie gegenüberstehen.

    
Will Hartung 24.10.2014 18:10
quelle
2

Wir hatten ein ähnliches Problem, das auf Caching zurückzuführen ist. Wir haben eine sehr gute Lektüre über Abfragepläne gelesen.

SQL Server speichert Ausführungspläne zwischen, und Sie können sie mit

sehen %Vor%

Was für uns funktionierte war, den zwischengespeicherten Ausführungsplan für die langsamen Abfragen zu ignorieren.

Was passiert, ist wahrscheinlich, dass die Optimierungsstufe bei verschiedenen Abfragen die Parameterwerte der Abfragen berücksichtigt. Da es in manchen Fällen sinnvoller ist, einen anderen Ausführungsplan zu verwenden.

Wenn der Ausführungsplan zwischengespeichert wurde und ein Cache-Treffer auftritt (mit einer vorbereiteten Anweisung, die Parameter ignoriert), ist der Ausführungsplan möglicherweise für dieselbe Abfrage mit anderen Parametern nicht optimal.

Um dies zu überprüfen, können Sie versuchen, einige Abfragen wiederherzustellen und festzustellen, ob Sie einen anderen Ausführungsplan für die gleiche Abfrage mit anderen Parametern erhalten.

Wenn das der Fall ist, gibt es mehrere Dinge, die Sie tun können:

  • Für ein sofortiges Ergebnis fügen Sie einen Kompilierungshinweis OPTION (RECOMPILE) zu Ihrer Anfrage hinzu. Dies wird die Abfrage jedes Mal neu kompilieren, aber möglicherweise bereits viel schneller als das, was Sie derzeit haben. Aus der Dokumentation:
  

RECOMPILE - Weist das SQL Server-Datenbankmodul an, den für die Abfrage generierten Plan nach der Ausführung zu verwerfen, wodurch der Abfrageoptimierer gezwungen ist, einen Abfrageplan neu zu kompilieren, wenn die gleiche Abfrage das nächste Mal ausgeführt wird. Ohne Angabe von RECOMPILE speichert das Datenbankmodul Abfragepläne zwischen und speichert sie erneut. Bei der Kompilierung von Abfrageplänen verwendet der RECOMPILE-Abfragehinweis die aktuellen Werte aller lokalen Variablen in der Abfrage . Wenn die Abfrage in einer gespeicherten Prozedur enthalten ist, werden die aktuellen Werte an alle Parameter übergeben.

  • Cache ungültig machen (siehe Recompiling Execution Plans ). Die Möglichkeiten zum Ungültigmachen des Caches sind. Hinweis: Einige davon werden in azurblau nicht unterstützt :
  
  1. Änderungen an einer Tabelle oder Ansicht, auf die von der Abfrage verwiesen wird   (ALTER TABLE und ALTER VIEW).

  2.   
  3. Änderungen, die an einer einzelnen Prozedur vorgenommen wurden und die alle löschen würden   Pläne für diese Prozedur aus dem Cache (ALTER PROCEDURE).

  4.   
  5. Ändert alle vom Ausführungsplan verwendeten Indizes.

  6.   
  7. Aktualisierungen zu Statistiken, die vom Ausführungsplan verwendet werden,   generiert entweder explizit aus einer Anweisung,   wie UPDATE STATISTICS, oder automatisch generiert.

  8.   
  9. Löschen eines vom Ausführungsplan verwendeten Indexes.

  10.   
  11. Ein expliziter Aufruf von sp_recompile.

  12.   
  13. Große Anzahl von Änderungen an Schlüsseln (generiert durch INSERT   oder DELETE-Anweisungen von anderen Benutzern, die a ändern   Tabelle, auf die von der Abfrage verwiesen wird).

  14.   
  15. Bei Tabellen mit Triggern, wenn die Anzahl der Zeilen in   Die eingefügten oder gelöschten Tabellen wachsen erheblich.

  16.   
  17. Ausführen einer gespeicherten Prozedur mit der Option WITH RECOMPILE.

  18.   
  • Optimiere den Plan manuell mithilfe von OPTIMIZE FOR hints (habe es nicht versucht).

  • Verwenden Sie nach dem Klassifizieren der Parameter separate Abfragen.

Reut Sharabani 26.09.2016 07:39
quelle
1

Vielleicht kann dieser Link aus der Microsoft-Dokumentation Ihnen helfen, Ihr Problem zu lösen: Ссылка

Vor allem im Abschnitt " Richtlinien zur Verwendung adaptiver Pufferung ":

Es gibt Fälle, in denen selectMethod = cursor anstelle von responseBuffering = adaptive vorteilhafter wäre, beispielsweise:

Wenn Ihre Anwendung nur eine schreibgeschützte Nur-Lese-Ergebnismenge verarbeitet, z. B. jede Zeile nach einer Benutzereingabe liest, verwenden Sie selectMethod = cursor anstelle von responseBuffering = adaptive könnte dazu beitragen, die Ressourcennutzung durch SQL Server zu reduzieren.

Wenn Ihre Anwendung zwei oder mehr Nur-Lese-Ergebnismengen gleichzeitig in derselben Verbindung verarbeitet, verwenden Sie selectMethod = cursor anstelle von responseBuffering = adaptive kann dazu beitragen, den Speicher zu reduzieren, den der Treiber während der Verarbeitung dieser Ergebnismengen benötigt.

In beiden Fällen müssen Sie den Aufwand beim Erstellen, Lesen und Schließen der Servercursor berücksichtigen.

    
stacky 24.10.2014 15:48
quelle