Éviter les curseurs sous Microsoft SQL ServerDate de publication : 20/05/2005
Par
SQLPro (autres articles) (CV) niveau : intermédiaire Les curseurs permettent de réaliser des traitements itératifs sur des jeux de résultats. Pour autant ils possèdent de nombreux inconvénients. Ils sont notamment gourmands en ressources et instable par nature... A travers les nombreux audits de bases de données que j'ai fait, mon constat est simple : 90% des curseurs utilisés dans les développements ne sont pas nécessaires ! Il est donc possible de les éviter la plupart du temps. Mais comment s'en passer ? nous allons le voir à travers trois exemples, et deux procèdures stockées non documentées de Microsoft... 1. Remplacer un curseur par une requête 2. Remplacer un curseur par une requete avec paramètre 3. Remplacer un curseur par un jeu de requête avec table temporaire 4. Procédures non documentées 1. Remplacer un curseur par une requête
Voici un cas classique : comment réaliser un cumul de valeurs ligne à ligne. Donnons nous un jeu d'essai simple mais coriace. Celui d'une partie de scrabble avec 3 joueurs, dont la table des scores est réalisée comme suit :
Pour réaliser le cumul, il vient à l'esprit d'ordonner le jeu de résultat dans l'ordre des tours et des participants et de prévoir autant de compteurs que de joueurs (au scrabble, la limite est de quatre) :
Il est parfaitement possible de remplacer un tel traitement à l'aide d'une requête SQL tout à fait classique. Voici une telle requête :
Elle propose de joindre la table sur elle même par une inéqui jointure afin de faire le cumul. Pensez donc à utiliser toutes les techniques de requêtes, comme les jointures non équi, les sous requêtes et particulièrement celles corélées. Une requête, même très complexe sera la plupart du temps plus efficace qu'un traitement iteratif à l'aide d'une boucle par curseur. Cela est dû à l'optimiseur. 2. Remplacer un curseur par une requete avec paramètre
Avec les données suivantes... La table T_JOUEUR est composé de la sorte :
...nous aimerions obtenir la liste concaténée des prénoms, par exemple : Marcel, Gérard, Victor, Eugène, Didier La solution classique utilisant un curseur est la suivante :
Mais il est parfaitement possible de ne pas utiliser de curseur pour obtenir un tel résultat.
En effet, il suffit de se rapeller qu'un simple SELECT parcoure toutes les lignes de la table.
Dès lors, on peut utiliser un SELECT d'affectation avec une variable pour empiler les prénoms
à la queue leu leu. Voici un tel code :
Les éléments importants à prendre en considération sont :
3. Remplacer un curseur par un jeu de requête avec table temporaire
Nous allons maintenant nous intéresser à réaliser une procédure
permettant de recalculer toutes statistiques de toutes les tables
de la base de données. Une telle procédure nécessite l'appel de
la commande UPDATE STATISTICS qui ne peut se faire que pour une
table donnée, d'ou le recours à un curseur :
Pour remplacer un tel code par une procédure sans curseur il faut
utiliser une astuce qui consiste à créer une table temporaire dans
laquelle nous allons puiser un élément à travailler à l'aide de la
clause spécifique à SQL server : TOP 1. Lorsque cet élément aura été
travaillé en lançant une requête dynamique, nous marquerons que
le travail a été effectué en donnant une valeur particulière à une
colonne spécialisement établie a cet effet lors de la création de
la table temporaire. A partir de cet instant, cette ligne va disparaitre du jeu appelé par le SELECT TOP 1. Petit à petit tout sera traité !
4. Procédures non documentées
MS SQL Server, est doté depuis la version 6.5 de deux procédures
non documentées permettant de réaliser un traitement pour chaque
base de données et pour chaque table dans une base donnée. Ces
procédures ont pour nom : sp_MSforeachdb et sp_MSforeachtable
(attention, respectez bien la casse exacte ci acant du nom des
procédures). Ces deux procédures acceptent en paramètre une chaîne de caractères qui sera exécutée pour chaque base ou pour chaque table. En bonus, la présence du signe ? (point d'interrogation) dans la chaîne de caractères sera remplacé par le nom de la base ou de la table. Attention cependant, dans le cas du nom de la table, ce dernier est toujours composé des deux parties nom_propriétaire.nom_table. Si vous ne désirez obtenir que la partie nom de table, il faudra u tiliser la fonction SUBSTRING combiné a la fonction CHARINDEX, de cette manière :
Voici deux exemples d'utilisation de ces fonctions :
(la procedure a été exécutée dans la base exemple Northwind) Attention cependant, qui dit procédure non documentée, dit portabilité suspecte, donc précautions. N'utilisez ces procédures, que dans un cadre léger et souple, par exemple une maintenance susceptible d'évoluer, et testez la non régression à chaque patch comme à chaque nouvelle version de MS SQL Server. Remerciements à Webman pour la relecture orthographique de cet article, ainsi qu'aux membres de la rubrique SGBD.
|
Copyright © 2005 Frédéric Brouard. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée.
Copyright © 2000-2012 - www.developpez.com