Vor-und Nachteile der Verwendung eines Cursors (in SQL Server)

7

Ich habe hier eine Frage gestellt Cursor in OLTP-Datenbanken (SQL Server) verwenden

wo Leute darauf geantwortet haben, dass Cursor niemals benutzt werden sollten.

Ich denke, dass Cursor sehr mächtige Werkzeuge sind, die verwendet werden sollen (ich glaube nicht, dass Microsoft Cursor für schlechte Entwickler unterstützt). Angenommen, Sie haben eine Tabelle, in der der Wert einer Spalte in einer Zeile vom Wert von abhängt die gleiche Spalte in der vorherigen Zeile. Wenn es ein einmaliger Back-End-Prozess ist, denken Sie nicht, dass die Verwendung eines Cursors eine akzeptable Wahl wäre?

Von meinem Kopf aus kann ich mir ein paar Szenarien vorstellen, in denen ich denke, dass es keine Schande sein sollte, Cursor zu verwenden. Bitte lassen Sie mich wissen, wenn Sie anders fühlen.

1 & gt; Ein einmaliger Back-End-Prozess zum Säubern schlechter Daten, der die Ausführung innerhalb weniger Minuten beendet. 2 & gt; Batch-Prozesse, die einmal in einem langen Zeitraum (etwa einmal pro Jahr) ausgeführt werden. Wenn es in den oben genannten Szenarien keine sichtbare Belastung für die anderen Prozesse gibt, wäre es nicht unangemessen, zusätzliche Stunden damit zu verbringen, Code zu schreiben, um Cursor zu vermeiden? Mit anderen Worten, in bestimmten Fällen ist die Zeit des Entwicklers wichtiger als die Leistung eines Prozesses, der sich kaum auf etwas anderes auswirkt.

Meiner Meinung nach wären dies einige Szenarien, in denen Sie ernsthaft versuchen sollten, die Verwendung eines Cursors zu vermeiden. 1 & gt; Eine gespeicherte Prozedur, die von einer Webseite aufgerufen wird, die sehr oft aufgerufen werden kann. 2 & gt; Ein SQL-Job, der mehrmals am Tag ausgeführt wird und eine Menge Ressourcen verbraucht.

Ich denke, es ist sehr oberflächlich, eine allgemeine Aussage zu machen, wie "Cursor niemals verwendet werden sollten", ohne die Aufgabe zu analysieren und sie gegen die Alternativen abzuwägen.

Bitte lassen Sie mich Ihre Gedanken wissen.

    
developer747 16.02.2012, 22:14
quelle

5 Antworten

11

Es gibt mehrere Szenarios, in denen Cursor tatsächlich bessere Ergebnisse erzielen als set-basierte Äquivalente. Es ist immer wichtig, Summen auszugeben - suchen Sie nach Itziks Worten (und ignorieren Sie alle, die SQL Server 2012 betreffen, das neue Fensterfunktionen hinzufügt, die Cursorn in dieser Situation eine Chance auf ihr Geld geben).

Eines der großen Probleme, die Menschen mit Cursors haben, ist, dass sie langsam arbeiten, sie verwenden temporären Speicher usw. Dies liegt teilweise daran, dass die Standardsyntax ein globaler Cursor mit allen Arten von ineffizienten Standardoptionen ist. Wenn du das nächste Mal etwas mit einem Cursor machst, der keine Dinge wie UPDATE...WHERE CURRENT OF erledigen muss (was ich in meiner ganzen Karriere vermeiden konnte), dann schüttele die beiden Syntaxoptionen:

%Vor%

Tatsächlich stellt die erste Version einen Fehler in der undokumentierten gespeicherten Prozedur sp_MSforeachdb dar, der dazu führt, dass Datenbanken übersprungen werden, wenn sich der Status einer Datenbank während der Ausführung ändert. Ich schrieb später meine eigene Version der gespeicherten Prozedur (siehe hier und hier ), die beide den Fehler behoben haben (einfach durch Verwendung der letzteren Version der obigen Syntax) und mehrere Parameter hinzugefügt haben, um zu steuern, welche Datenbanken ausgewählt werden sollen.

Viele Leute denken, dass eine Methode kein Cursor ist, weil sie nicht DECLARE CURSOR sagt. Ich habe gesehen, dass Leute argumentieren, dass eine while-Schleife schneller ist als ein Cursor ( was ich hoffe, dass ich hier zerstreut habe ) oder dass die Verwendung von FOR XML PATH zur Gruppenverkettung keine versteckte Cursoroperation ausführt. Wenn Sie in vielen Fällen auf den Plan schauen, wird dies die Wahrheit zeigen.

In vielen Fällen werden Cursor verwendet, wenn set-based geeigneter ist. Es gibt jedoch viele gültige Anwendungsfälle, in denen ein satzbasiertes Äquivalent viel komplizierter zu schreiben ist, damit der Optimierer einen Plan für beides generiert oder nicht (z. B. Wartungsaufgaben, bei denen Sie Tabellen durchlaufen, um Statistiken zu aktualisieren, Aufrufen einer gespeicherten Prozedur für jeden Wert in einem Ergebnis usw.). Dasselbe gilt für viele große Multitable-Abfragen, bei denen der Plan für den Optimizer zu monströs wird. In diesen Fällen kann es besser sein, einige der Zwischenergebnisse zuerst in eine temporäre Struktur auszugeben. Dasselbe gilt für einige set-basierte Äquivalente zu Cursorn (wie laufende Summen). Ich habe auch über den anderen Weg geschrieben, wo Leute fast immer instinktiv denken, eine while-Schleife / einen Cursor zu verwenden, und es gibt clever Set-basierte Alternativen, die viel besser sind .

UPDATE 2013-07-25

Ich wollte nur einige zusätzliche Blogposts, die ich über Cursors geschrieben habe, hinzufügen, welche Optionen Sie verwenden sollten, wenn Sie tun müssen und Set-basierte Abfragen anstelle von Schleifen zum Generieren verwenden Sätze:

Beste Ansätze für laufende Summen - für SQL Server 2012 aktualisiert

Welche Auswirkungen können verschiedene Cursor-Optionen haben?

Generieren Sie einen Satz oder eine Sequenz ohne Schleifen: [Teil 1] [Teil 2] [Teil 3]

    
Aaron Bertrand 17.02.2012, 04:32
quelle
6

Das Problem mit Cursorn in SQL Server ist, dass die Engine intern gesetzt ist, im Gegensatz zu anderen DBMS wie Oracle, die intern cursor-basiert sind. Dies bedeutet, dass beim Erstellen eines Cursors in SQL Server temporärer Speicher erstellt werden muss und die mengenbasierte Ergebnismenge in den temporären Cursorspeicher kopiert werden muss. Sie können sehen, warum dies auf Anhieb teuer wäre, ganz zu schweigen von jeder zeilenweisen Verarbeitung, die Sie möglicherweise über den Cursor selbst vornehmen. Die Quintessenz ist, dass Set-basierte Verarbeitung effizienter ist, und oft kann Ihre Cursor-basierte Operation besser mit einem CTE oder Temp-Tabelle durchgeführt werden.

Es gibt Fälle, in denen ein Cursor wahrscheinlich akzeptabel ist, wie Sie für einmalige Operationen gesagt haben. Die gebräuchlichste Verwendung, die ich mir vorstellen kann, ist ein Wartungsplan, bei dem Sie möglicherweise alle Datenbanken eines Servers durchlaufen, der verschiedene Wartungsaufgaben ausführt. Solange Sie Ihre Verwendung einschränken und nicht ganze Anwendungen in der RBAR-Verarbeitung (Zeile für Zeile) entwerfen, sollten Sie in Ordnung sein.

    
Pam Lahoud 16.02.2012 22:51
quelle
3

Im Allgemeinen sind Cursor eine schlechte Sache. In einigen Fällen ist es jedoch praktischer, einen Cursor zu verwenden, und in einigen Fällen ist es sogar noch schneller, einen zu verwenden. Ein gutes Beispiel ist ein Cursor durch eine Kontakttabelle, der E-Mails basierend auf einigen Kriterien sendet. (Um die Frage nicht zu stellen, ob das Senden einer E-Mail von Ihrem DBMS eine gute Idee ist - nehmen wir einfach an, dass es für das Problem zur Hand ist.) Es gibt keine Möglichkeit, dieses Set-based zu schreiben. Sie könnten einige Tricks anwenden, um eine Set-basierte Lösung zum Generieren von dynamischem SQL zu finden, aber eine echte set-basierte Lösung existiert nicht.

Eine Berechnung mit der vorherigen Zeile kann jedoch mit einem Self-Join durchgeführt werden. Das ist normalerweise immer noch schneller als ein Cursor.

In allen Fällen müssen Sie den Aufwand für die Entwicklung einer schnelleren Lösung ausgleichen. Wenn es niemanden interessiert, wenn Sie Läufe in einer Minute oder in einer Stunde verarbeiten, verwenden Sie, was die Aufgabe am schnellsten erledigt. Wenn Sie ein Dataset durchlaufen, das im Laufe der Zeit wie eine Tabelle [Aufträge] wächst, versuchen Sie, möglichst von einem Cursor wegzubleiben. Wenn Sie sich nicht sicher sind, führen Sie einen Leistungstest durch, bei dem eine Cursor-Basis mit einer Set-basierten Lösung in mehreren signifikant unterschiedlichen Datengrößen verglichen wird.

    
Sebastian Meine 17.02.2012 01:56
quelle
0

Sie sind für Dinge wie dynamisches SQL-Pivotieren erforderlich, aber Sie sollten versuchen, sie zu vermeiden, wann immer dies möglich ist.

    
Vince Pergolizzi 17.02.2012 20:50
quelle
0

Ich hatte Cursor wegen ihrer langsamen Leistung immer nicht gemocht. Ich habe jedoch festgestellt, dass ich die verschiedenen Cursortypen nicht vollständig verstanden habe und dass Cursor in bestimmten Fällen eine praktikable Lösung darstellen.

Wenn Sie ein Geschäftsproblem haben, das nur durch die Verarbeitung von jeweils einer Zeile gelöst werden kann, ist ein Cursor angebracht.

Um die Leistung mit dem Cursor zu verbessern, ändern Sie den Typ des Cursors, den Sie verwenden. Etwas, das ich nicht wusste, ist, wenn Sie nicht angeben, welcher Typ von Cursor Sie deklarieren, erhalten Sie den Typ Dynamic Optimistic, der am langsamsten für die Performance ist, weil er viel Arbeit unter der Haube macht . Wenn Sie den Cursor jedoch als einen anderen Typ deklarieren, z. B. als statischen Cursor, hat er eine sehr gute Leistung.

Siehe diese Artikel für eine ausführlichere Erklärung:

Die Wahrheit über Cursor: Teil I

Die Wahrheit über Cursor: Teil II

Die Wahrheit über Cursor: Teil III

Ich denke, der größte Nachteil gegenüber den Cursors ist die Performance. Allerdings würde es wahrscheinlich an zweiter Stelle stehen, keine Aufgabe in einem Set-basierten Ansatz auszulegen. Drittens wäre Lesbarkeit und Layout der Aufgaben, da sie normalerweise nicht viele hilfreiche Kommentare haben.

SQL Server wurde optimiert, um den satzbasierten Ansatz auszuführen. Sie schreiben die Abfrage, um eine Ergebnismenge von Daten zurückzugeben, z. B. eine Verknüpfung für Tabellen, aber die SQL Server-Ausführungsengine bestimmt, welche Verknüpfung verwendet werden soll: Zusammenführungsjoin, Verschachtelte Schleifenverbindung oder Hash-Verknüpfung. SQL Server ermittelt den optimalen Verbindungsalgorithmus anhand der beteiligten Spalten, des Datenvolumens, der Indexstruktur und der Menge der Werte in den beteiligten Spalten. Daher ist die Verwendung eines satzbasierten Ansatzes im Allgemeinen der beste Ansatz in Bezug auf die Leistung gegenüber dem Ansatz des Verfahrenscursors.

    
James Drinkard 21.08.2013 14:31
quelle

Tags und Links