276
Chapitre 8. Optimisation du code SQL
Nous pourrions conserver la syntaxe de la première procédure, et forcer la recompilation, mais la requête, comportant de multiples variables, reste difficile à analyser.
Parfois, la syntaxe dynamique, malgré ses défauts, en terme de sécurité et de lisibilité,
est intéressante pour les performances.
8.3.3 Éviter les curseurs
Le curseur est une construction T-SQL permettant de traiter séquentiellement un
jeu de résultat côté serveur. Parce qu’il viole la syntaxe ensembliste du langage SQL,
et ainsi court-circuite toute possibilité d’optimisation par SQL Server, il est l’ennemi
public numéro un des performances du code SQL. En présence de curseurs, la
meilleure décision d’optimisation à prendre est de les remplacer par du code ensembliste, ce qui est la plupart du temps possible. Bien que les curseurs soient en euxmêmes « optimisables » (par le choix de curseurs en type READ ONLY ou FAST_FORWARD
notamment), nous pensons préférable de présenter des moyens de s’en passer.
La plupart des curseurs qu’on peut rencontrer dans du code de production sont
créés par manque de connaissance des possibilités du langage SQL. Le code d’administration est un problème différent. On y rencontre des curseurs pour automatiser
des maintenances sur les objets, ce qui est acceptable, compte tenu de la fréquence
d’utilisation, et du choix de fenêtres d’administration favorables.
Souvent, les curseurs sont utilisés pour effectuer des traitements ou des vérifications complexes sur les lignes. Ils peuvent en général être remplacés par de simples
jointures, ou un passage par une table temporaire. Le but est de les récrire en code
ensembliste. Si le traitement ligne par ligne est néanmoins nécessaire, il est souvent
plus intéressant d’effectuer une boucle WHILE avec des SELECT, qui se révèlent plus
efficaces. Voici un exemple simple de curseur, et son remplacement par une boucle
WHILE :
-- curseur
DECLARE cur CURSOR FAST_FORWARD
FOR SELECT ContactId FROM Person.Contact ORDER BY ContactId
DECLARE @CurrentContactID int
OPEN cur
FETCH NEXT FROM cur INTO @CurrentContactID
WHILE (@@fetch_status <> -1)
BEGIN
IF (@@fetch_status <> -2)
PRINT @CurrentContactID
FETCH NEXT FROM cur INTO @CurrentContactID
END
CLOSE cur
DEALLOCATE cur
GO
Chapitre 8. Optimisation du code SQL
Nous pourrions conserver la syntaxe de la première procédure, et forcer la recompilation, mais la requête, comportant de multiples variables, reste difficile à analyser.
Parfois, la syntaxe dynamique, malgré ses défauts, en terme de sécurité et de lisibilité,
est intéressante pour les performances.
8.3.3 Éviter les curseurs
Le curseur est une construction T-SQL permettant de traiter séquentiellement un
jeu de résultat côté serveur. Parce qu’il viole la syntaxe ensembliste du langage SQL,
et ainsi court-circuite toute possibilité d’optimisation par SQL Server, il est l’ennemi
public numéro un des performances du code SQL. En présence de curseurs, la
meilleure décision d’optimisation à prendre est de les remplacer par du code ensembliste, ce qui est la plupart du temps possible. Bien que les curseurs soient en euxmêmes « optimisables » (par le choix de curseurs en type READ ONLY ou FAST_FORWARD
notamment), nous pensons préférable de présenter des moyens de s’en passer.
La plupart des curseurs qu’on peut rencontrer dans du code de production sont
créés par manque de connaissance des possibilités du langage SQL. Le code d’administration est un problème différent. On y rencontre des curseurs pour automatiser
des maintenances sur les objets, ce qui est acceptable, compte tenu de la fréquence
d’utilisation, et du choix de fenêtres d’administration favorables.
Souvent, les curseurs sont utilisés pour effectuer des traitements ou des vérifications complexes sur les lignes. Ils peuvent en général être remplacés par de simples
jointures, ou un passage par une table temporaire. Le but est de les récrire en code
ensembliste. Si le traitement ligne par ligne est néanmoins nécessaire, il est souvent
plus intéressant d’effectuer une boucle WHILE avec des SELECT, qui se révèlent plus
efficaces. Voici un exemple simple de curseur, et son remplacement par une boucle
WHILE :
-- curseur
DECLARE cur CURSOR FAST_FORWARD
FOR SELECT ContactId FROM Person.Contact ORDER BY ContactId
DECLARE @CurrentContactID int
OPEN cur
FETCH NEXT FROM cur INTO @CurrentContactID
WHILE (@@fetch_status <> -1)
BEGIN
IF (@@fetch_status <> -2)
PRINT @CurrentContactID
FETCH NEXT FROM cur INTO @CurrentContactID
END
CLOSE cur
DEALLOCATE cur
GO
