Remarque :Cet article a été initialement publié uniquement dans notre eBook, Techniques hautes performances pour SQL Server, Volume 3. Vous pouvez en savoir plus sur nos eBooks ici.
Il y a plus de trois ans, j'ai écrit un article sur les options de curseur dans SQL Server et pourquoi vous devriez remplacer les valeurs par défaut :
- Quel impact les différentes options de curseur peuvent-elles avoir ?
Je voulais publier un suivi pour réitérer que - bien que vous ne devriez jamais simplement accepter les valeurs par défaut - vous devriez vraiment réfléchir aux options les plus applicables à votre scénario. Je voulais également clarifier quelques éléments qui sont apparus dans les commentaires sur ce post.
Andrew Kelly a soulevé un grand point, et c'est qu'un STATIC
le curseur fait une copie unique des résultats, les place dans tempdb, puis évite tout problème de concurrence pouvant avoir un impact sur un DYNAMIC
le curseur. Une option n'est pas clairement gagnante sur l'autre dans tous les cas; par exemple, vous pouvez avoir beaucoup de curseurs (ou des curseurs avec de très grands ensembles de résultats) et/ou une base de données tempdb déjà surchargée et ne souhaitez pas y décharger de stress supplémentaire. Mais c'est quelque chose qui mérite d'être testé.
Fabiano a également soulevé un excellent point que les deux DYNAMIC
et FAST_FORWARD
les curseurs peuvent être vulnérable au problème de l'Halloween (discuté par Paul White dans une série en 4 parties, commençant ici). Paul a également commenté que FAST_FORWARD
peut ne pas être vulnérable au problème, selon que l'optimiseur a choisi un plan statique ou dynamique (Marc Friedman de Microsoft explique cela en détail ici).
Enfin, je voulais souligner que tous les curseurs par défaut ne sont pas créés égaux. J'ai exécuté des tests et vérifié comment SQL Server a décidé de définir les options de curseur dans divers scénarios (validé à l'aide de sys.dm_exec_cursors
fonction de gestion dynamique). Le code est assez simple :
DECLARE c CURSOR FOR [...blah blah...]; SELECT properties FROM sys.dm_exec_cursors(@@SPID);
Voici les résultats des scénarios que j'ai testés :
La requête du curseur est basée sur… | Tapez | Concurrence | Portée |
---|---|---|---|
une constante (FOR SELECT 1 ou FOR SELECT SYSDATETIME() ) | Instantané | Lecture seule | Global |
une table #temp / ##temp | Dynamique | Optimiste | Global |
une table/vue utilisateur | Dynamique | Optimiste | Global |
une vue catalogue / DMV | Instantané | Lecture seule | Global |
une jointure #tmp -> table/vue utilisateur | Dynamique | Optimiste | Global |
une jointure #tmp -> vue catalogue / DMV | Instantané | Lecture seule | Global |
une jointure table/vue utilisateur -> vue catalogue/DMV | Instantané | Lecture seule | Global |
Crédit là où le crédit est dû :cette enquête a été déclenchée par une réponse de Jeroen Mostert sur Stack Overflow.
Vous devez donc savoir que les options par défaut de votre curseur, si vous ne les remplacez pas, peuvent être différentes selon la requête sous-jacente au curseur. Si vous vous attendez à un comportement spécifique dans un ou tous les cas, prenez l'habitude de spécifier explicitement les options souhaitées.
Mais vraiment, le point est…
… arrêtez d'utiliser les curseurs. Il y a vraiment très peu de problèmes aujourd'hui où la meilleure solution est un curseur, surtout si vous êtes sur SQL Server 2012 ou supérieur - où à peu près tous les problèmes traditionnellement résolus par des curseurs peuvent être résolus en utilisant des améliorations des fonctions de fenêtre. Si vous pensez toujours que vous devez utiliser des curseurs, veuillez suivre les conseils de cet article et de son prédécesseur pour déterminer les options à utiliser.