Ich kann verstehen, dass ich aufgrund des Overheads und der Unannehmlichkeiten vermeiden möchte, einen Cursor verwenden zu müssen, aber es sieht so aus, als ob es eine ernsthafte Cursor-Phobie-Manie gibt, bei der die Leute große Anstrengungen unternehmen, um zu vermeiden, dass sie einen verwenden müssen.
In einer Frage wurde beispielsweise gefragt, wie mit einem Cursor etwas offensichtlich Triviales zu tun ist, und die akzeptierte Antwort wurde unter Verwendung einer rekursiven Abfrage mit allgemeinem Tabellenausdruck (CTE) mit einer rekursiven benutzerdefinierten Funktion vorgeschlagen, obwohl dies die Anzahl der Zeilen begrenzt, die verarbeitet werden können, auf 32 (aufgrund des rekursiven Funktionsaufruflimits im SQL Server). Dies scheint mir eine schreckliche Lösung für die Langlebigkeit des Systems zu sein, ganz zu schweigen von einer enormen Anstrengung, nur um die Verwendung eines einfachen Cursors zu vermeiden.
Was ist der Grund für diesen wahnsinnigen Hass? Hat eine "bekannte Autorität" eine Fatwa gegen Cursor erlassen? Lauert ein unaussprechliches Übel im Herzen von Cursorn, die die Moral von Kindern verfälschen oder so?
Wiki-Frage, mehr an der Antwort interessiert als an der Wiederholung.
Verwandte Informationen:
SQL Server-Schnellvorlauf-Cursor
EDIT: Lassen Sie mich genauer sein: Ich verstehe, dass Cursor nicht anstelle von normalen relationalen Operationen verwendet werden sollten ; das ist ein Kinderspiel. Was ich nicht verstehe, sind Leute, die sich alle Mühe geben, um Cursor zu vermeiden, als hätten sie Cooties oder ähnliches, selbst wenn ein Cursor eine einfachere und / oder effizientere Lösung ist. Es ist der irrationale Hass, der mich verblüfft, nicht die offensichtlichen technischen Effizienzvorteile.
32
ist Unsinn. Vermutlich denken Sie an rekursive Trigger und das Maximum@@NESTLEVEL
von32
. Sie kann in der AbfrageOPTION (MAXRECURSION N)
mit Standard100
und0
unbegrenzter Bedeutung festgelegt werden.Antworten:
Der "Overhead" mit Cursorn ist lediglich Teil der API. Cursor sind die Funktionsweise von Teilen des RDBMS unter der Haube. Oft
CREATE TABLE
undINSERT
habenSELECT
Anweisungen, und die Implementierung ist die offensichtliche interne Cursor-Implementierung.Durch die Verwendung übergeordneter "satzbasierter Operatoren" werden die Cursorergebnisse zu einer einzigen Ergebnismenge gebündelt, was weniger API-Hin- und Her bedeutet.
Cursor sind älter als moderne Sprachen, die erstklassige Sammlungen bieten. Das alte C, COBOL, Fortran usw. mussten Zeilen einzeln verarbeiten, da es keinen Begriff für "Sammlung" gab, der weit verbreitet werden konnte. Java, C #, Python usw. verfügen über erstklassige Listenstrukturen, die Ergebnismengen enthalten.
Das langsame Problem
In einigen Kreisen sind die relationalen Verknüpfungen ein Rätsel, und die Leute schreiben verschachtelte Cursor anstatt einer einfachen Verknüpfung. Ich habe wirklich epische Nested-Loop-Operationen gesehen, die als viele, viele Cursor geschrieben wurden. RDBMS-Optimierung aufheben. Und sehr langsam laufen.
Einfache SQL-Umschreibungen, um verschachtelte Cursorschleifen durch Verknüpfungen zu ersetzen, und eine einzelne flache Cursorschleife können dazu führen, dass Programme zum 100. Mal ausgeführt werden. [Sie dachten, ich sei der Gott der Optimierung. Ich habe nur verschachtelte Schleifen durch Joins ersetzt. Noch verwendete Cursor.]
Diese Verwirrung führt oft zu einer Anklage gegen Cursor. Es ist jedoch nicht der Cursor, sondern der Missbrauch des Cursors, der das Problem darstellt.
Das Größenproblem
Für wirklich epische Ergebnismengen (dh das Speichern einer Tabelle in eine Datei) sind Cursor unerlässlich. Die satzbasierten Operationen können keine wirklich großen Ergebnismengen als einzelne Sammlung im Speicher materialisieren.
Alternativen
Ich versuche so viel wie möglich eine ORM-Ebene zu verwenden. Das hat aber zwei Zwecke. Zunächst werden die Cursor von der ORM-Komponente verwaltet. Zweitens wird die SQL von der Anwendung in eine Konfigurationsdatei getrennt. Es ist nicht so, dass die Cursor schlecht sind. Es ist so, dass das Codieren all dieser Öffnen, Schließen und Abrufen keine wertschöpfende Programmierung ist.
quelle
Cursor führen dazu, dass Menschen eine prozedurale Denkweise übermäßig auf eine satzbasierte Umgebung anwenden.
Und sie sind langsam !!!
Von SQLTeam :
quelle
Es gibt eine Antwort oben, die besagt: "Cursor sind die langsamste Möglichkeit, auf Daten in SQL Server zuzugreifen ... Cursor sind mehr als dreißigmal langsamer als satzbasierte Alternativen."
Diese Aussage mag unter vielen Umständen zutreffen, ist aber als pauschale Aussage problematisch. Zum Beispiel habe ich Cursor in Situationen gut eingesetzt, in denen ich einen Aktualisierungs- oder Löschvorgang ausführen möchte, der viele Zeilen einer großen Tabelle betrifft, die konstante Produktionslesevorgänge empfängt. Das Ausführen einer gespeicherten Prozedur, die diese Aktualisierungen zeilenweise ausführt, ist schneller als satzbasierte Operationen, da die satzbasierte Operation mit der Leseoperation in Konflikt steht und schreckliche Sperrprobleme verursacht (und das Produktionssystem möglicherweise vollständig zerstört). in Extremfällen).
In Ermangelung anderer Datenbankaktivitäten sind satzbasierte Vorgänge universell schneller. In Produktionssystemen kommt es darauf an.
quelle
Cursor werden normalerweise von SQL-Entwicklern an Orten verwendet, an denen satzbasierte Operationen besser wären. Insbesondere wenn Benutzer SQL nach dem Erlernen einer traditionellen Programmiersprache lernen, führt die Mentalität "Über diese Datensätze iterieren" dazu, dass Benutzer Cursor unangemessen verwenden.
Die meisten seriösen SQL-Bücher enthalten ein Kapitel, in dem die Verwendung von Cursorn beschrieben wird. Gut geschriebene machen deutlich, dass Cursor ihren Platz haben, aber nicht für satzbasierte Operationen verwendet werden sollten.
Es gibt offensichtlich Situationen, in denen Cursor die richtige Wahl sind oder zumindest eine richtige Wahl.
quelle
Der Optimierer kann die relationale Algebra häufig nicht verwenden, um das Problem zu transformieren, wenn eine Cursormethode verwendet wird. Oft ist ein Cursor eine gute Möglichkeit, ein Problem zu lösen, aber SQL ist eine deklarative Sprache, und die Datenbank enthält viele Informationen, von Einschränkungen bis hin zu Statistiken und Indizes, sodass der Optimierer viele Optionen zur Lösung des Problems hat Problem, während ein Cursor die Lösung ziemlich explizit steuert.
quelle
In Oracle führen PL / SQL-Cursor nicht zu Tabellensperren, und es ist möglich, das Sammeln und Abrufen von Massen zu verwenden.
In Oracle 10 der häufig verwendete implizite Cursor
ruft implizit 100 Zeilen gleichzeitig ab. Explizites Sammeln / Abrufen von Massen ist ebenfalls möglich.
PL / SQL-Cursor sind jedoch ein letzter Ausweg. Verwenden Sie sie, wenn Sie ein Problem mit satzbasiertem SQL nicht lösen können.
Ein weiterer Grund ist die Parallelisierung. Für die Datenbank ist es einfacher, große satzbasierte Anweisungen zu parallelisieren als zeilenweisen Imperativcode. Aus demselben Grund wird die funktionale Programmierung immer beliebter (Haskell, F #, Lisp, C # LINQ, MapReduce ...). Die funktionale Programmierung erleichtert die Parallelisierung. Die Anzahl der CPUs pro Computer steigt, sodass die Parallelisierung immer mehr zum Problem wird.
quelle
Im Allgemeinen ist die Leistung von Code mit Cursorn in einer relationalen Datenbank um eine Größenordnung schlechter als bei satzbasierten Operationen.
quelle
Die obigen Antworten haben die Wichtigkeit des Schließens nicht genug betont. Ich bin kein großer Fan von Cursorn, weil sie oft zu Sperren auf Tabellenebene führen.
quelle
Für das, was es wert ist, habe ich gelesen, dass die "eine" Stelle, an der ein Cursor sein satzbasiertes Gegenstück ausführt, eine laufende Summe ist. Bei einer kleinen Tabelle begünstigt die Geschwindigkeit, mit der die Zeilen über die Reihenfolge nach Spalten summiert werden, die satzbasierte Operation. Mit zunehmender Zeilengröße der Tabelle wird der Cursor jedoch schneller, da der laufende Gesamtwert einfach zum nächsten Durchgang der Tabelle übertragen werden kann Schleife. Nun, wo Sie eine laufende Summe machen sollten, ist ein anderes Argument ...
quelle
Ich stimme dem Artikel auf dieser Seite zu:
http://weblogs.sqlteam.com/jeffs/archive/2008/06/05/sql-server-cursor-removal.aspx
quelle
Abgesehen von den (Nicht-) Leistungsproblemen denke ich, dass das größte Versagen von Cursorn darin besteht, dass das Debuggen schmerzhaft ist. Insbesondere im Vergleich zu Code in den meisten Clientanwendungen, in denen das Debuggen vergleichsweise einfach und die Sprachfunktionen in der Regel viel einfacher sind. Tatsächlich behaupte ich, dass fast alles, was man in SQL mit einem Cursor macht, wahrscheinlich überhaupt erst in der Client-App passieren sollte.
quelle
Können Sie dieses Cursor-Beispiel posten oder auf die Frage verlinken? Es gibt wahrscheinlich einen noch besseren Weg als einen rekursiven CTE.
Zusätzlich zu anderen Kommentaren verursachen Cursor bei unsachgemäßer Verwendung (was häufig der Fall ist) unnötige Seiten- / Zeilensperren.
quelle
Sie hätten Ihre Frage wahrscheinlich nach dem zweiten Absatz abschließen können, anstatt die Leute "verrückt" zu nennen, nur weil sie einen anderen Standpunkt vertreten als Sie, und auf andere Weise zu versuchen, Fachleute zu verspotten, die möglicherweise einen sehr guten Grund haben, sich so zu fühlen, wie sie es tun.
In Bezug auf Ihre Frage gibt es zwar sicherlich Situationen, in denen ein Cursor erforderlich sein kann, aber meiner Erfahrung nach entscheiden Entwickler, dass ein Cursor weitaus häufiger "verwendet" werden muss, als dies tatsächlich der Fall ist. Die Wahrscheinlichkeit, dass jemand auf der Seite von zu viel Verwendung von Cursorn irrt, anstatt sie nicht zu verwenden, wenn er sollte, ist meiner Meinung nach VIEL höher.
quelle
Grundsätzlich 2 Codeblöcke, die dasselbe tun. Vielleicht ist es ein etwas seltsames Beispiel, aber es beweist den Punkt. SQL Server 2005:
Das einzelne Update dauert 156 ms, während der Cursor 2016 ms benötigt.
quelle