Hinweis:Dieser Beitrag wurde ursprünglich nur in unserem eBook High Performance Techniques for SQL Server, Band 3 veröffentlicht. Sie können sich hier über unsere eBooks informieren.
Vor über drei Jahren schrieb ich einen Beitrag über Cursoroptionen in SQL Server und warum Sie die Standardwerte überschreiben sollten:
- Welche Auswirkungen können verschiedene Cursoroptionen haben?
Ich wollte ein Follow-up veröffentlichen, um zu wiederholen, dass Sie – obwohl Sie niemals nur die Standardeinstellungen akzeptieren sollten – wirklich darüber nachdenken sollten, welche Optionen für Ihr Szenario am besten geeignet sind. Ich wollte auch einige Punkte klarstellen, die in den Kommentaren zu diesem Beitrag auftauchten.
Andrew Kelly hat einen großartigen Punkt angesprochen, und das ist ein STATIC
Cursor erstellt eine einmalige Kopie der Ergebnisse, legt sie in tempdb ab und vermeidet dann Parallelitätsprobleme, die sich auf DYNAMIC
auswirken können Mauszeiger. Eine Option ist nicht in allen Fällen ein klarer Gewinner gegenüber der anderen; Beispielsweise haben Sie möglicherweise viele Cursor (oder Cursor mit sehr großen Ergebnismengen) und/oder eine bereits überlastete tempdb und möchten dort keinen zusätzlichen Stress auslagern. Aber es ist etwas, das es wert ist, getestet zu werden.
Fabiano brachte auch einen großartigen Punkt zur Sprache, dass sowohl DYNAMIC
und FAST_FORWARD
Cursor können anfällig für das Halloween-Problem sein (besprochen von Paul White in einer 4-teiligen Serie, beginnend hier). Paul hat auch das FAST_FORWARD
kommentiert möglicherweise nicht anfällig für das Problem, je nachdem, ob der Optimierer einen statischen oder dynamischen Plan gewählt hat (Microsofts Marc Friedman geht hier sehr detailliert darauf ein).
Abschließend möchte ich darauf hinweisen, dass nicht alle Standard-Cursor gleich sind. Ich habe einige Tests durchgeführt und überprüft, wie SQL Server entschieden hat, Cursoroptionen in einer Vielzahl von Szenarien festzulegen (validiert mit sys.dm_exec_cursors
dynamische Verwaltungsfunktion). Der Code ist ziemlich einfach:
DECLARE c CURSOR FOR [...blah blah...]; SELECT properties FROM sys.dm_exec_cursors(@@SPID);
Hier sind die Ergebnisse für die von mir getesteten Szenarien:
Cursor-Abfrage basiert auf… | Typ | Gleichzeitigkeit | Geltungsbereich |
---|---|---|---|
eine Konstante (FOR SELECT 1 oder FOR SELECT SYSDATETIME() ) | Schnappschuss | Nur lesen | Global |
eine #temp / ##temp-Tabelle | Dynamisch | Optimistisch | Global |
eine Benutzertabelle/Ansicht | Dynamisch | Optimistisch | Global |
eine Katalogansicht / DMV | Schnappschuss | Nur lesen | Global |
a join #tmp -> Benutzertabelle / Ansicht | Dynamisch | Optimistisch | Global |
a join #tmp -> Katalogansicht / DMV | Schnappschuss | Nur lesen | Global |
a join user table/view -> catalog view/DMV | Schnappschuss | Nur lesen | Global |
Gutschrift wem Ehre gebührt – diese Untersuchung wurde durch eine Antwort von Jeroen Mostert auf Stack Overflow ausgelöst.
Sie sollten sich also bewusst sein, dass die Standardoptionen für Ihren Cursor, wenn Sie sie nicht überschreiben, je nach der dem Cursor zugrunde liegenden Abfrage unterschiedlich sein können. Wenn Sie in einigen oder allen Fällen ein bestimmtes Verhalten erwarten, gewöhnen Sie sich an, die gewünschten Optionen explizit anzugeben.
Aber wirklich, der Punkt ist…
… aufhören, Cursor zu verwenden. Heutzutage gibt es wirklich nur sehr wenige Probleme, bei denen die beste Lösung ein Cursor ist, insbesondere wenn Sie auf SQL Server 2012 oder besser arbeiten – wo fast jedes Problem, das traditionell durch Cursor gelöst wird, durch Erweiterungen der Fensterfunktionen gelöst werden kann. Wenn Sie immer noch der Meinung sind, dass Sie Cursor verwenden müssen, befolgen Sie bitte die Ratschläge in diesem Beitrag und seinem Vorgänger, um zu bestimmen, welche Optionen Sie verwenden sollten.