Cursors in SQL stellen gebruikers in staat om rijen per rij door een dataset te lopen en specifieke acties uit te voeren op elke record, wat lijkt op iteratie in programmeren. Dit is handig voor complexe stapsgewijze logica die niet mogelijk is met een enkele SQL-query (bijvoorbeeld stapsgewijze berekeningen met veranderingen in externe toestanden).
Voorbeeld van een cursor:
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;
Voordelen:
Nadelen en valkuilen:
Kan een cursor binnen een trigger worden gebruikt? Wat voor gevolgen kan dit hebben voor de prestaties van de database?
Antwoord en voorbeeld: Het is mogelijk om een cursor binnen een trigger te gebruiken, maar het wordt ten zeerste afgeraden — elke DML-operatie kan een cursor activeren voor elke aangetaste rij, wat leidt tot een exponentiële toename van verzoeken en vergrendelingen.
CREATE TRIGGER UpdateBalance ON Accounts AFTER INSERT AS DECLARE c CURSOR FOR SELECT id FROM inserted; -- slecht! OPEN c; -- ...
Verhaal
Project: Samenvatting van bestellingen in de detailhandel. De taak was om de voorraad te tellen als een partij gebreken vertoonde — daaropvolgende partijen vereisen handmatige herberekening via kortingupdates. Een cursor werd gebruikt om door de partijen te lopen. Later bleek dat bij meervoudige uitvoering de stroom urenlang werd geblokkeerd, de serverlading exponentieel toenam en lock contention leidde tot storingen.
Verhaal
Project: ERP, gegevensmigratie. In de importverwerkingsprocedure werd foutafhandelingslogica via een cursor toegevoegd. Men hield er geen rekening mee dat een cursor op 5 miljoen rijen 40 keer trager werkt dan vergelijkbare batchverwerking met set-gebaseerde UPDATE + CASE. Vanwege de trage migratie verschoof de deadline.
Verhaal
Project: Facturering voor een financiële onderneming. In de trigger voor de update van de transactietabel werd een cursor toegevoegd om de nieuwe aggregaat saldo te berekenen. In productie leidde dit tot "STOP THE WORLD" — het invoeren van zelfs één record vertraagde de werking van de service vanwege het activeren van een genestelde cursor voor veel rijen.