Poznámka:Tento příspěvek byl původně publikován pouze v naší elektronické knize, High Performance Techniques for SQL Server, Volume 3. O našich elektronických knihách se můžete dozvědět zde.
Před více než třemi lety jsem napsal příspěvek o možnostech kurzoru na serveru SQL Server a o tom, proč byste měli přepsat výchozí hodnoty:
- Jaký dopad mohou mít různé možnosti kurzoru?
Chtěl jsem zveřejnit následnou zprávu, abych zopakoval, že – i když byste nikdy neměli přijímat pouze výchozí hodnoty – měli byste se skutečně zamyslet nad tím, které možnosti jsou pro váš scénář nejvhodnější. Také jsem chtěl objasnit několik věcí, které se objevily v komentářích k tomuto příspěvku.
Andrew Kelly uvedl skvělou věc, a to, že STATIC
kurzor vytvoří jednorázovou kopii výsledků, vloží je do databáze tempdb a poté se vyhne všem problémům se souběžností, které by mohly ovlivnit DYNAMIC
kurzor. Jedna možnost není ve všech případech jasným vítězem nad druhou; můžete mít například hodně kurzorů (nebo kurzorů s velmi velkými sadami výsledků) a/nebo již přetíženou databázi tempdb a nechcete tam ukládat žádné další napětí. Ale je to něco, co stojí za to vyzkoušet.
Fabiano také uvedl skvělý bod, který je DYNAMIC
a FAST_FORWARD
kurzory mohou být zranitelný vůči problému Hallowe'en (diskutovaný Paulem Whitem ve 4dílné sérii, která začíná zde). Paul také poznamenal, že FAST_FORWARD
nemusí být náchylné k problému, v závislosti na tom, zda optimalizátor zvolil statický nebo dynamický plán (Marc Friedman ze společnosti Microsoft se o tom podrobně věnuje zde).
Nakonec jsem chtěl poukázat na to, že ne všechny výchozí kurzory jsou vytvořeny stejně. Provedl jsem několik testů a zkontroloval, jak se SQL Server rozhodl nastavit možnosti kurzoru v různých scénářích (ověřeno pomocí sys.dm_exec_cursors
funkce dynamického řízení). Kód je docela jednoduchý:
DECLARE c CURSOR FOR [...blah blah...]; SELECT properties FROM sys.dm_exec_cursors(@@SPID);
Zde jsou výsledky pro scénáře, které jsem testoval:
Dotaz kurzoru je založen na… | Typ | Souběh | Rozsah |
---|---|---|---|
konstanta (FOR SELECT 1 nebo FOR SELECT SYSDATETIME() ) | Snímek | Pouze pro čtení | Globální |
tabulka #temp / ##temp | Dynamické | Optimistický | Globální |
uživatelská tabulka / pohled | Dynamické | Optimistický | Globální |
zobrazení katalogu / DMV | Snímek | Pouze pro čtení | Globální |
a join #tmp -> uživatelská tabulka / pohled | Dynamické | Optimistický | Globální |
a join #tmp -> zobrazení katalogu / DMV | Snímek | Pouze pro čtení | Globální |
připojit uživatelskou tabulku / zobrazení -> zobrazení katalogu / DMV | Snímek | Pouze pro čtení | Globální |
Kredit tam, kde je splatný kredit – toto vyšetřování vyvolala odpověď od Jeroena Mosterta na Stack Overflow.
Měli byste si tedy být vědomi toho, že výchozí možnosti pro váš kurzor, pokud je nepřepíšete, se mohou lišit v závislosti na dotazu ležícím pod kurzorem. Pokud v některém nebo všech případech očekáváte specifické chování, zvykněte si explicitně specifikovat požadované možnosti.
Ale ve skutečnosti jde o…
…přestaňte používat kurzory. Dnes je opravdu jen velmi málo problémů, kde je nejlepším řešením kurzor, zvláště pokud používáte SQL Server 2012 nebo lepší – kde téměř každý problém tradičně řešený kurzory lze vyřešit pomocí vylepšení funkcí okna. Pokud stále máte pocit, že potřebujete používat kurzory, vezměte prosím na vědomí rady v tomto příspěvku a jeho předchůdci, abyste určili, které možnosti byste měli použít.