ProgrammationDéveloppeur SQL

Décrivez les caractéristiques, les avantages et les pièges du traitement en série des données à l'aide de curseurs (CURSOR) en SQL. Quand est-il judicieux d'utiliser des curseurs, et quand vaut-il mieux les éviter au profit d'opérations basées sur des ensembles (set-based) ? Donnez un exemple d'utilisation d'un curseur.

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

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 :

  • Permettent de réaliser des procédures complexes où chaque ligne nécessite un traitement ou une vérification des conditions externes.
  • Pratiques pour l'intégration avec des systèmes hérités ou des migrations nécessitant un contrôle étape par étape.

Inconvénients et pièges :

  • Les curseurs sont généralement TRÈS lents : le traitement se fait ligne par ligne au lieu d'être basé sur des ensembles ;
  • Consomment beaucoup de ressources, peuvent bloquer des tables ;
  • Ne sont pas évolutifs pour de gros volumes de données ;
  • Il est préférable de réécrire en SQL basé sur des ensembles ou d'utiliser un traitement par lots.

Question piège.

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.