sql Serverabfrage wird langsam von Java ausgeführt

7

Ich habe ein Java-Programm, das eine Reihe von Abfragen für eine SQL Server-Datenbank ausführt. Die erste dieser Abfragen, die eine Ansicht abfragen, gibt etwa 750.000 Datensätze zurück. Ich kann die Abfrage über SQL Server Management Studio ausführen, und ich bekomme Ergebnisse in etwa 30 Sekunden. Ich habe jedoch das Programm gestartet, um letzte Nacht zu laufen. Als ich heute morgen nachgesehen habe, hatte diese Abfrage nach etwa 15 Stunden noch immer keine Ergebnisse an das Java-Programm zurückgegeben.

Ich habe Zugriff auf die Datenbank, um alles zu tun, was ich will, aber ich bin mir nicht sicher, wie ich mit der Fehlersuche beginnen soll. Was sollte man tun, um herauszufinden, was eine solche Situation verursacht? Ich bin kein dba und kenne mich mit dem Toolset für SQL-Server nicht aus, so dass Sie mehr Details darüber erfahren könnten, wie Sie das tun können, was Sie vielleicht vorschlagen würden.

enthält den Code

%Vor%

EDIT1:

Nun, es ist eine Weile her, und das wurde abgelenkt, aber dieses Problem ist zurück. Ich schaute in upgrade von jdbc-Treiber v 1.2 zu 2.0, aber wir sind auf jdk 1.4 fest, und v 2.0 erfordern jdk 1.5, so dass ein Nichtstarter ist. Jetzt schaue ich mir die Eigenschaften meiner Verbindungszeichenfolge an. Ich sehe 2, die nützlich sein könnten.

%Vor%

Momentan, mit dem Latenz-Problem, laufe ich mit dem Cursor als selectMethod und mit dem Standard für responseBuffering, das voll ist. Werden diese Eigenschaften wahrscheinlich geändert? Wenn ja, was wären die idealen Einstellungen? Ich denke basierend auf dem, was ich online finde, dass die Verwendung einer direkten Auswahlmethode und adaptiver Antwortpufferung mein Problem lösen könnte. irgendwelche Gedanken?

EDIT2:

Ich habe die Änderung beider Verbindungszeichenfolgenparameter beendet, indem ich die Standardmethode select (direkt) verwendet und responseBuffering als adaptiv angegeben habe. Dies funktioniert am besten für mich und lindert die Latenzprobleme, die ich sah. Danke für die Hilfe.

    
shsteimer 07.06.2009, 02:36
quelle

12 Antworten

4

Stellen Sie sicher, dass Ihr JDBC-Treiber so konfiguriert ist, dass er eine direkte Verbindung und keine cursor-basierte Verbindung verwendet. Sie können Ihre JDBC-Verbindungs-URL posten, wenn Sie sich nicht sicher sind.

Stellen Sie sicher, dass Sie eine Nur-Lese-Ergebnismenge verwenden, die nur gelesen werden kann (dies ist die Standardeinstellung, wenn Sie sie nicht festlegen).

Stellen Sie sicher, dass Sie aktualisierte JDBC-Treiber verwenden.

Wenn das alles nicht funktioniert, sollten Sie sich den sql-Profiler ansehen und versuchen, die sql-Abfrage zu erfassen, während der jdbc-Treiber die Anweisung ausführt, und diese Anweisung im Management-Studio ausführen, um festzustellen, ob ein Unterschied besteht.

Da Sie so viele Daten abrufen, sollten Sie auch versuchen, sicher zu sein, dass Sie keine Speicher- / Speicherbereinigungsverzögerungen auf der JVM haben (obwohl in diesem Fall die Zeitdiskrepanz nicht wirklich erklärt wird).

    
Yishai 07.06.2009, 04:18
quelle
13

Ich hatte ein ähnliches Problem mit einer sehr einfachen Anfrage (SELECT. FROM. WHERE =.), die bei Verwendung einer jdbc-Verbindung in Java bis zu 10 Sekunden dauert, um eine einzelne Zeile zurückzugeben, während nur 0,01s in sqlshell genommen werden. Das Problem war das gleiche, ob ich den offiziellen MS SQL-Treiber oder den JTDS-Treiber verwendete.

Die Lösung war, diese Eigenschaft in der jdbc-URL einzurichten: sendStringParametersAsUnicode = false

Vollständiges Beispiel, wenn Sie den offiziellen MS SQL-Treiber verwenden: jdbc: sqlserver: // ihrserver; instanzname = ihrInstanz; datenbankname = ihrDBName; sendStringParametersAsUnicode = false;

Anweisungen, wenn Sie verschiedene jdbc-Treiber verwenden und detailliertere Informationen zum Problem finden Sie hier: Ссылка

  

SQL Server unterscheidet seine Datentypen, die Unicode unterstützen, von denen, die nur ASCII unterstützen. Zum Beispiel sind die Zeichendatentypen, die Unicode unterstützen, nchar, nvarchar, longnvarchar, wobei ihre ASCII-Zähleranteile char, varchar bzw. longvarchar sind. Standardmäßig senden alle JDBC-Treiber von Microsoft die Zeichenfolgen im Unicode-Format an den SQL Server, unabhängig davon, ob der Datentyp der entsprechenden Spalte, die im SQL Server definiert ist, Unicode unterstützt oder nicht. Wenn die Datentypen der Spalten Unicode unterstützen, ist alles glatt. In Fällen, in denen die Datentypen der Spalten Unicode nicht unterstützen, treten jedoch schwerwiegende Leistungsprobleme auf, insbesondere beim Datenabruf. SQL Server versucht, Nicht-Unicode-Datentypen in der Tabelle in Unicode-Datentypen zu konvertieren, bevor der Vergleich durchgeführt wird. Wenn darüber hinaus ein Index für die Nicht-Unicode-Spalte existiert, wird er ignoriert. Dies würde letztendlich zu einem vollständigen Tabellenscan während des Datenabrufs führen, wodurch die Suchabfragen drastisch verlangsamt würden.

In meinem Fall hatte ich 30M + Datensätze in der Tabelle, aus der ich suchte. Die Dauer zum Abschließen der Anforderung betrug mehr als 10 Sekunden, nach dem Anwenden der Eigenschaft ungefähr 0,01 Sekunden.

Hoffe das wird jemandem helfen!

    
Khopa 30.09.2015 13:36
quelle
7

Es scheint, dass dies auf Ihre spezielle Situation nicht zutrifft, aber ich wollte eine andere mögliche Erklärung für jemanden bereitstellen, der nach diesem Problem sucht.

Ich hatte gerade ein ähnliches Problem, bei dem eine Abfrage, die direkt in SQL Server ausgeführt wurde, 1 Minute gedauert hat, während die gleiche Abfrage über eine Java-vorbereitete Statusmeldung 5 Minuten gedauert hat. Ich habe es auf die Tatsache zurückgeführt, dass es als vorbereitete Aussage gemacht wurde.

Wenn Sie eine Abfrage direkt in SQL Server ausführen, stellen Sie ihr eine nicht parametrisierte Abfrage zur Verfügung, in der sie alle Suchkriterien zur Optimierungszeit kennt. In meinem Fall beinhaltete mein Suchkriterium einen Datumsbereich, und SQL Server konnte es betrachten, entschied, "dass der Datumsbereich riesig ist, nutze den Datumsindex nicht" und wählte dann etwas viel besseres.

Wenn ich die gleiche Abfrage über eine Java-Prepared-Anweisung ausfühle, habe ich zu dem Zeitpunkt, zu dem SQL Server die Abfrage optimiert, noch keinen der Parameterwerte angegeben. Daher muss er raten, welcher Index verwendet werden soll . Im Fall meines Datumsbereichs, wenn es für eine kleine Reichweite optimiert wird und ich ihm eine große Auswahl gebe, wird es langsamer als es möglich war. Genauso, wenn es für eine große Bandbreite optimiert wird und ich ihm eine kleine gebe, wird es wieder langsamer laufen, als es könnte.

Um zu demonstrieren, dass dies tatsächlich das Problem war, habe ich versucht, als Experiment zu zeigen, was ich für die Verwendung der Option "OPTIMIEREN FÜR" von SQL Server optimieren sollte. Als ich ihm sagte, einen winzigen Datumsbereich zu verwenden, nahm meine Java-Abfrage (die eigentlich einen großen Datumsbereich hatte) tatsächlich doppelt so lange wie zuvor (10 Minuten im Gegensatz zu 5 Minuten vorher und im Gegensatz zu 1 Minute in SQL Server) ). Als ich ihm meine genauen Daten für die Optimierung erzählte, war die Ausführungszeit identisch zwischen der Java Prepared-Anweisung.

Meine Lösung bestand also darin, die genauen Daten in die Abfrage zu schreiben. Dies funktionierte für mich, weil dies nur eine einmalige Aussage war. Das PreparedStatement sollte nicht wiederverwendet werden, sondern lediglich zur Parametrisierung der Werte, um SQL-Injection zu vermeiden. Da diese Daten von einem java.sql.Date-Objekt stammten, musste ich mir keine Gedanken über meine Datumswerte machen, die den Injektionscode enthielten.

Aber für eine Aussage, die wiederverwendet werden muss, würde eine harte Codierung der Daten nicht funktionieren. Vielleicht wäre es eine bessere Option, mehrere vorbereitete Anweisungen zu erstellen, die für verschiedene Zeiträume optimiert sind (einen für einen Tag, einen für eine Woche, einen für einen Monat, einen für ein Jahr und einen für ein Jahrzehnt ... oder vielleicht Sie brauche nur 2 oder 3 Optionen ... ich weiß es nicht) und führe dann für jede Abfrage die eine vorbereitete Anweisung aus, deren Zeitbereich am besten mit dem Bereich in der tatsächlichen Abfrage übereinstimmt.

Das funktioniert natürlich nur, wenn Ihre Datumsbereiche gleichmäßig verteilt sind. Wenn 80% Ihrer Datensätze im letzten Jahr und 20% in den letzten 10 Jahren verteilt waren, ist die "Mehrfachabfrage basierend auf der Bereichsgröße" möglicherweise nicht die beste Lösung. Sie müssten Ihre Abfragen basierend auf bestimmten Bereichen oder etwas optimieren. Sie müssten das durch einen Versuch mit einem Fehler herausfinden.

    
ldkronos 22.10.2014 13:39
quelle
3

Wenn die Abfrage parametrisiert ist, kann sie ein fehlender Parameter oder ein Parameter sein, der mit der falschen Funktion eingestellt ist, z. setLong für String usw. Versuchen Sie, Ihre Abfrage mit allen Parametern auszuführen, die fest in den Abfragetext geschrieben sind, ohne dass ? ein Problem darstellt.

    
Leon Fleysher 04.01.2011 16:05
quelle
1

Ich weiß, dass dies eine alte Frage ist, aber da es eines der ersten Ergebnisse bei der Suche nach diesem Problem ist, dachte ich, ich sollte posten, was für mich funktioniert hat. Ich hatte eine Abfrage, die weniger als 10 Sekunden dauerte, wenn ich SQL Server JDBC-Treiber verwendete, aber mehr als 4 Minuten, wenn ich jTDS verwendete. Ich habe alle hier genannten Vorschläge ausprobiert und nichts davon machte einen Unterschied. Das Einzige, was funktioniert hat, ist das Hinzufügen zu der URL "; prepareSQL = 1"

Siehe Hier für mehr

    
Sol 02.01.2015 16:12
quelle
0

Wenn Sie so viele Daten zurückholen, benötigen Sie viel Zeit. Sie sollten wahrscheinlich einen Weg finden, so viele Daten in Ihrer Anwendung zu keiner bestimmten Zeit zu benötigen. Seite die Daten oder verwenden Sie Lazy Loading zum Beispiel. Ohne weitere Details zu dem, was Sie erreichen möchten, ist es schwer zu sagen.

    
JP Alioto 07.06.2009 02:43
quelle
0

Die Tatsache, dass es bei der Ausführung aus dem Management-Studio zu schnell ist, kann auf einen falsch zwischengespeicherten Abfrageplan und veraltete Indizes zurückzuführen sein (z. B. aufgrund eines großen Imports oder Löschvorgangs). Gibt es alle 750K-Datensätze schnell in SSMS zurück?

Versuchen Sie, Ihre Indizes neu zu erstellen (oder wenn das zu lange dauern würde, aktualisieren Sie Ihre Statistiken); und vielleicht den Prozedurcache leeren (Vorsicht, wenn dies ein Produktionssystem ist ...): DBCC FREEPROCCACHE

    
Mitch Wheat 07.06.2009 02:53
quelle
0

Um mit dem Debuggen zu beginnen, wäre es gut festzustellen, ob sich der Problembereich in der Datenbank oder in der App befindet. Haben Sie versucht, die Abfrage so zu ändern, dass sie ein viel kleineres Ergebnis liefert? Wenn das nicht zurückkommt, würde ich vorschlagen, die Art und Weise, wie Sie von Java auf die Datenbank zugreifen, zu tarieren.

    
akf 07.06.2009 03:53
quelle
0

Versuchen Sie, die Abrufgröße der Anweisung anzupassen und selectMethod des Cursors

zu versuchen

Ссылка

Wir hatten Probleme mit großen Resultsets, die mysql verwendeten und benötigten, um das Resultset wie im folgenden Link beschrieben zu streamen.

Ссылка

    
objects 07.06.2009 04:20
quelle
0

Zitat aus den MS Adaptive Pufferrichtlinien:

  

Vermeiden Sie die Verwendung der Verbindungszeichenfolgeneigenschaft selectMethod = cursor, damit die Anwendung eine sehr große Ergebnismenge verarbeiten kann. Die adaptive Pufferfunktion ermöglicht es Anwendungen, sehr große Nur-Lese-Ergebnismengen ohne Lesezugriff zu verarbeiten, ohne einen Server-Cursor zu verwenden. Beachten Sie, dass beim Festlegen von selectMethod = cursor alle schreibgeschützten Nur-Lese-Ergebnismengen betroffen sind, die von dieser Verbindung erzeugt werden. Mit anderen Worten: Wenn Ihre Anwendung kurze Ergebnismengen routinemäßig mit wenigen Zeilen verarbeitet, werden beim Erstellen, Lesen und Schließen eines Servercursors für jede Ergebnismenge sowohl auf der Clientseite als auch auf der Serverseite mehr Ressourcen verwendet als in selectMethod ist nicht auf den Cursor eingestellt.

Und

  

Es gibt Fälle, in denen die Verwendung von selectMethod = cursor anstelle von responseBuffering = adaptive vorteilhafter wäre, wie zum Beispiel:

     
  • Wenn Ihre Anwendung nur eine schreibgeschützte Nur-Lese-Ergebnismenge verarbeitet, wie z. B. das Lesen jeder Zeile nach einer Benutzereingabe, kann die Verwendung von selectMethod = cursor anstelle von responseBuffering = adaptive die Ressourcennutzung durch SQL Server verringern.

  •   
  • Wenn Ihre Anwendung zwei oder mehr Nur-Lese-Ergebnismengen gleichzeitig auf derselben Verbindung verarbeitet, kann die Verwendung von selectMethod = cursor anstelle von responseBuffering = adaptive dazu beitragen, den vom Treiber während des Vorgangs benötigten Speicherplatz zu reduzieren Verarbeitung dieser Ergebnismengen.

  •   

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

Siehe mehr: Ссылка

    
eugenevd 13.03.2013 09:37
quelle
0

Manchmal könnte es an der Art und Weise liegen, wie Parameter an das Abfrageobjekt gebunden sind. Ich fand, dass der folgende Code sehr langsam ist, wenn er vom Java-Programm ausgeführt wird.

%Vor%

Sobald ich den "gelöschten" Parameter entferne und diese "DELETED" Zeichenfolge direkt an die Abfrage angehängt habe, wurde er super schnell. Es kann sein, dass SQL Server erwartet, dass alle Parameter gebunden sind, um den optimierten Plan zu bestimmen.

    
Shehan Simen 08.02.2018 03:02
quelle
-1

Wie lange dauert es mit SQLWB? Wenn die Java-Version viel langsamer ist, dann würde ich ein paar Dinge überprüfen:

  1. Sie sollten die beste Leistung mit einem Nur-Lese-Read-Only-ResultSet erzielen.
  2. Ich erinnere mich, dass die älteren JDBC-Treiber von MSFT langsam waren. Stellen Sie sicher, dass Sie das Neueste-N-Größte verwenden. Ich denke, es gibt einen generischen SQL Server für SQL 2005.
Brian Reiter 07.06.2009 03:53
quelle