Les curseurs en SQL permettent de parcourir ligne par ligne un ensemble de données et d'exécuter certaines actions sur chaque enregistrement, ce qui ressemble à une itération en programmation. Cela est utile pour une logique complexe étape par étape, impossible avec un simple SQL (par exemple, des calculs pas à pas nécessitant un changement d'état externe).
Exemple de curseur :
DECLARE my_cursor CURSOR FOR SELECT id, balance FROM Accounts WHERE isActive = 1; OPEN my_cursor; DECLARE @id INT, @bal DECIMAL(10,2); FETCH NEXT FROM my_cursor INTO @id, @bal; WHILE @@FETCH_STATUS = 0 BEGIN UPDATE Accounts SET balance = @bal * 1.05 WHERE id = @id; FETCH NEXT FROM my_cursor INTO @id, @bal; END CLOSE my_cursor; DEALLOCATE my_cursor;
Avantages :
Inconvénients et pièges :
Peut-on utiliser un curseur à l'intérieur d'un déclencheur ? Quelles conséquences cela peut-il avoir sur les performances de la base de données ?
Réponse et exemple : L'utilisation d'un curseur à l'intérieur d'un déclencheur est possible, mais fortement déconseillée - chaque opération DML peut lancer un curseur pour chaque ligne affectée, ce qui conduit à une augmentation exponentielle des requêtes et des blocages.
CREATE TRIGGER UpdateBalance ON Accounts AFTER INSERT AS DECLARE c CURSOR FOR SELECT id FROM inserted; -- pas bien ! OPEN c; -- ...
Histoire
Projet : Résumé des commandes dans le commerce de détail. Il y avait pour tâche de compter les stocks si un lot était trouvé défectueux - les lots suivants nécessitent un nouveau comptage manuel via une mise à jour des remises. Un curseur a été utilisé pour parcourir les lots. Il a été découvert par la suite que lors de multiples exécutions, le flux était bloqué pendant des heures, la charge sur le serveur augmentait de manière exponentielle, et la contention des locks entraînait des pannes.
Histoire
Projet : ERP, migration des données. Dans le processus de traitement de l'importation, un traitement des erreurs a été ajouté via un curseur. Ils n'ont pas pris en compte que sur 5 millions de lignes, un curseur fonctionne 40 fois plus lentement qu'un traitement par lot similaire avec des mises à jour basées sur des ensembles + CASE. En raison de la lente migration, les délais ont été repoussés.
Histoire
Projet : Facturation d'une entreprise financière. Un curseur a été ajouté au déclencheur de mise à jour de la table des mouvements de fonds pour calculer le nouveau solde agrégé. En production, cela a conduit à "STOP THE WORLD" - l'insertion d'un seul enregistrement a ralenti le service en raison du lancement d'un curseur imbriqué sur de nombreuses lignes.