Opmerking:dit bericht is oorspronkelijk alleen gepubliceerd in ons eBook, High Performance Techniques for SQL Server, Volume 3. U kunt hier meer te weten komen over onze eBooks.
Meer dan drie jaar geleden schreef ik een bericht over cursoropties in SQL Server en waarom je de standaardinstellingen zou moeten overschrijven:
- Welke impact kunnen verschillende cursoropties hebben?
Ik wilde een vervolg plaatsen om te herhalen dat - hoewel je nooit zomaar de standaardinstellingen moet accepteren - je echt moet nadenken over welke opties het meest van toepassing zijn op jouw scenario. Ik wilde ook een paar items verduidelijken die naar voren kwamen in de reacties op dat bericht.
Andrew Kelly bracht een geweldig punt naar voren, en dat is dat een STATIC
cursor maakt een eenmalige kopie van de resultaten, plaatst ze in tempdb en vermijdt vervolgens gelijktijdigheidsproblemen die van invloed kunnen zijn op een DYNAMIC
cursor. De ene optie is niet in alle gevallen een duidelijke winnaar boven de andere; u heeft bijvoorbeeld veel cursors (of cursors met zeer grote resultatensets) en/of een al overbelaste tempdb en wilt daar geen extra stress ontlasten. Maar het is iets dat het testen waard is.
Fabiano bracht ook een geweldig punt naar voren dat zowel DYNAMIC
en FAST_FORWARD
cursors kunnen kwetsbaar zijn voor het Halloween-probleem (besproken door Paul White in een 4-delige serie, te beginnen hier). Paul merkte ook op dat FAST_FORWARD
mogelijk niet kwetsbaar voor het probleem, afhankelijk van of de optimizer een statisch of dynamisch plan heeft gekozen (Marc Friedman van Microsoft gaat hier uitgebreid op in).
Ten slotte wilde ik erop wijzen dat niet alle standaardcursors gelijk zijn gemaakt. Ik heb wat tests uitgevoerd en gecontroleerd hoe SQL Server besloot om cursoropties in te stellen onder verschillende scenario's (gevalideerd met behulp van de sys.dm_exec_cursors
dynamische managementfunctie). De code is vrij eenvoudig:
DECLARE c CURSOR FOR [...blah blah...]; SELECT properties FROM sys.dm_exec_cursors(@@SPID);
Dit zijn de resultaten voor de scenario's die ik heb getest:
Cursorquery is gebaseerd op... | Type | Gelijktijdigheid | Reikwijdte |
---|---|---|---|
een constante (FOR SELECT 1 of FOR SELECT SYSDATETIME() ) | Momentopname | Alleen-lezen | Globaal |
een #temp / ##temp tabel | Dynamisch | Optimistisch | Globaal |
een gebruikerstabel / weergave | Dynamisch | Optimistisch | Globaal |
een catalogusweergave / DMV | Momentopname | Alleen-lezen | Globaal |
een join #tmp -> gebruikerstabel / weergave | Dynamisch | Optimistisch | Globaal |
een join #tmp -> catalogusweergave / DMV | Momentopname | Alleen-lezen | Globaal |
een gebruikerstabel / weergave -> catalogusweergave / DMV | Momentopname | Alleen-lezen | Globaal |
Krediet waar krediet verschuldigd is - dit onderzoek werd veroorzaakt door een antwoord van Jeroen Mostert op Stack Overflow.
U moet er dus rekening mee houden dat de standaardopties voor uw cursor, als u ze niet overschrijft, kunnen verschillen afhankelijk van de query die aan de cursor ten grondslag ligt. Als u in een of alle gevallen een bepaald gedrag verwacht, maak er dan een gewoonte van om expliciet de gewenste opties te specificeren.
Maar het punt is eigenlijk...
... stop met het gebruik van cursors. Er zijn tegenwoordig echt heel weinig problemen waarbij de beste oplossing een cursor is, vooral als je SQL Server 2012 of beter gebruikt - waar zowat elk probleem dat traditioneel door cursors wordt opgelost, kan worden opgelost met behulp van verbeteringen aan vensterfuncties. Als je nog steeds het gevoel hebt dat je cursors moet gebruiken, volg dan het advies in dit bericht en zijn voorganger om te bepalen welke opties je moet gebruiken.