Cursor
Ein Cursor ist ein Datenbankobjekt, das als Zeiger auf eine bestimmte Position innerhalb einer Ergebnismenge einer SQL-Abfrage fungiert und die zeilenweise Verarbeitung einzelner Datensätze ermöglicht.
Auf dieser Seite
- Warum braucht man Cursor?
- Der Lebenszyklus eines Cursors
- Cursor-Typen
- Praktisches Beispiel in T-SQL
- Cursor in Oracle PL/SQL
- Performance: Cursor vs. mengenbasierte Operationen
- Wann solltest du Cursor verwenden?
- Cursor in verschiedenen Datenbanksystemen
- Cursor in der IHK-Prüfung
- Quellen und weiterführende Links
Ein Cursor ist ein Datenbankobjekt, das als Zeiger auf eine bestimmte Position innerhalb einer Ergebnismenge (Resultset) einer SQL-Abfrage fungiert. Während SQL grundsätzlich mengenorientiert arbeitet und komplette Datensätze auf einmal verarbeitet, ermöglichen Cursor die zeilenweise Verarbeitung einzelner Datensätze, ähnlich wie ein Dateizeiger in der klassischen Programmierung.
Das Konzept ist besonders dann nützlich, wenn du für jeden Datensatz eine individuelle, komplexe Verarbeitung durchführen musst, die sich nicht einfach in einer einzigen SQL-Anweisung ausdrücken lässt. Als Fachinformatiker für Anwendungsentwicklung wirst du Cursor vor allem in Stored Procedures und bei der Implementierung komplexer Geschäftslogik einsetzen.
Warum braucht man Cursor?
Relationale Datenbanken arbeiten nach dem Prinzip der Mengenverarbeitung: Eine SQL-Abfrage gibt alle passenden Zeilen als Gesamtergebnis zurück. Prozedurale Programmiersprachen hingegen arbeiten oft zeilenweise mit Daten. Diese Diskrepanz wird als Impedance Mismatch bezeichnet, und genau hier kommen Cursor ins Spiel.
Typische Anwendungsfälle für Cursor sind:
- Komplexe Geschäftslogik: Wenn für jeden Datensatz individuelle Berechnungen oder Validierungen nötig sind
- Zeilenweise Datenverarbeitung: Bei der schrittweisen Verarbeitung großer Datenmengen
- Interaktive Anwendungen: Wenn Benutzer durch Datensätze navigieren (z.B. Produktlisten)
- Datenmigrationen: Bei der Transformation von Daten zwischen verschiedenen Systemen
- Reporting: Für komplexe Berichte, die Zeile für Zeile aufgebaut werden
Der Lebenszyklus eines Cursors
Ein Cursor durchläuft einen klar definierten Lebenszyklus mit fünf Phasen. Das Verständnis dieser Phasen ist grundlegend für die korrekte Arbeit mit Cursorn.
1. DECLARE - Cursor deklarieren
In der ersten Phase wird der Cursor mit einem Namen versehen und die zugehörige SELECT-Abfrage definiert. Hier legst du auch fest, welchen Typ der Cursor haben soll und ob er nur lesend oder auch schreibend auf die Daten zugreifen darf.
2. OPEN - Cursor öffnen
Beim Öffnen wird die SELECT-Abfrage ausgeführt und die Ergebnismenge erstellt. Der Cursor-Zeiger wird vor den ersten Datensatz positioniert. Je nach Cursor-Typ wird das Resultset komplett in den Speicher geladen oder bei Bedarf abgerufen.
3. FETCH - Daten abrufen
Mit FETCH holst du den nächsten (oder bei scrollbaren Cursorn einen beliebigen) Datensatz aus der Ergebnismenge. Die Werte werden in Variablen übertragen, die du dann in deiner Programmlogik verwenden kannst. Der Cursor bewegt sich automatisch zur nächsten Position.
4. CLOSE - Cursor schließen
Nach der Verarbeitung wird der Cursor geschlossen. Dabei wird die Ergebnismenge freigegeben, aber die Cursor-Definition bleibt erhalten. Du kannst den Cursor später erneut öffnen, falls nötig.
5. DEALLOCATE - Ressourcen freigeben
Im letzten Schritt wird die Cursor-Definition vollständig entfernt und alle zugehörigen Ressourcen werden freigegeben. Dies ist wichtig für die Speicherverwaltung und sollte nie vergessen werden.
Cursor-Typen
Datenbanksysteme bieten verschiedene Cursor-Typen mit unterschiedlichen Eigenschaften. Die Wahl des richtigen Typs beeinflusst sowohl die Funktionalität als auch die Performance deiner Anwendung.
Forward-Only Cursor
Der einfachste und effizienteste Cursor-Typ. Er kann nur vorwärts durch die Daten navigieren, vom ersten zum letzten Datensatz. Da kein Scrolling unterstützt wird, verbraucht er minimal Ressourcen. Dieser Typ wird auch Firehose Cursor genannt und ist die beste Wahl für einfache, sequenzielle Verarbeitung.
Static Cursor
Erstellt beim Öffnen eine vollständige Momentaufnahme der Daten. Änderungen an den zugrundeliegenden Tabellen werden nicht sichtbar, der Cursor zeigt immer den Zustand zum Zeitpunkt des Öffnens. Das garantiert Konsistenz, benötigt aber mehr Speicher und kann bei großen Datenmengen langsam sein.
Dynamic Cursor
Das Gegenteil des Static Cursors: Er zeigt immer die aktuellsten Daten an. Alle INSERT-, UPDATE- und DELETE-Operationen anderer Benutzer werden sofort sichtbar. Dies ist ideal für Echtzeitanwendungen, kostet aber mehr Performance wegen der ständigen Synchronisation mit der Datenbank.
Keyset-Driven Cursor
Ein Kompromiss zwischen Static und Dynamic: Beim Öffnen wird ein Keyset (Sammlung von Primärschlüsseln) erstellt. Die eigentlichen Datenwerte werden erst beim FETCH aus der Datenbank geholt. Updates an bestehenden Zeilen sind sichtbar, neue Zeilen (INSERTs) hingegen nicht.
Praktisches Beispiel in T-SQL
Das folgende Beispiel zeigt einen typischen Cursor in Microsoft SQL Server, der alle Datenbanken sichert:
-- Variablen deklarieren
DECLARE @dbName VARCHAR(100)
DECLARE @backupPath VARCHAR(500)
-- Cursor deklarieren
DECLARE db_cursor CURSOR FOR
SELECT name
FROM sys.databases
WHERE name NOT IN ('tempdb')
-- Cursor oeffnen
OPEN db_cursor
-- Ersten Datensatz holen
FETCH NEXT FROM db_cursor INTO @dbName
-- Schleife durch alle Datensaetze
WHILE @@FETCH_STATUS = 0
BEGIN
-- Backup-Pfad erstellen
SET @backupPath = 'C:\Backup\' + @dbName + '.bak'
-- Backup ausfuehren
BACKUP DATABASE @dbName TO DISK = @backupPath
-- Naechsten Datensatz holen
FETCH NEXT FROM db_cursor INTO @dbName
END
-- Cursor schliessen und freigeben
CLOSE db_cursor
DEALLOCATE db_cursor
Die Systemvariable @@FETCH_STATUS zeigt den Status der letzten FETCH-Operation an: 0 bedeutet Erfolg, -1 zeigt einen Fehler an, und -2 bedeutet, dass die Zeile nicht mehr existiert.
Cursor in Oracle PL/SQL
Oracle bietet mit PL/SQL eine elegante Cursor-Syntax, besonders die Cursor FOR Loop, die vieles automatisch erledigt:
DECLARE
-- Cursor deklarieren
CURSOR emp_cursor IS
SELECT employee_id, first_name, salary
FROM employees
WHERE department_id = 10;
BEGIN
-- Cursor FOR Loop: oeffnet, fetcht und schliesst automatisch
FOR emp_rec IN emp_cursor LOOP
-- Fuer jeden Mitarbeiter: Gehalt um 10% erhoehen
UPDATE employees
SET salary = salary * 1.10
WHERE employee_id = emp_rec.employee_id;
DBMS_OUTPUT.PUT_LINE('Gehaltsanpassung fuer: ' || emp_rec.first_name);
END LOOP;
COMMIT;
END;
Die Cursor FOR Loop ist in Oracle die bevorzugte Methode, da sie den Code vereinfacht und häufige Fehler wie vergessene CLOSE-Anweisungen vermeidet.
Performance: Cursor vs. mengenbasierte Operationen
Wichtig: Cursor sind in der Regel deutlich langsamer als mengenbasierte SQL-Operationen. Der Grund liegt im wiederholten Kontextwechsel zwischen SQL- und Prozedur-Engine bei jedem FETCH. Ein Vergleich verdeutlicht dies:
| Anzahl Zeilen | Set-basiert | Cursor |
|---|---|---|
| 100 | 5 ms | 30 ms |
| 10.000 | 10 ms | 770 ms |
| 100.000 | 20 ms | 7.600 ms |
| 1.000.000 | 140 ms | 75 Sekunden |
Die Faustregel lautet: Vermeide Cursor, wenn eine mengenbasierte Lösung möglich ist. Ein UPDATE mit WHERE-Klausel ist fast immer schneller als ein Cursor, der jeden Datensatz einzeln aktualisiert.
Optimierungstechnik: BULK COLLECT
Wenn du Cursor verwenden musst, kann die BULK COLLECT-Technik (in Oracle und ähnliche Konstrukte in anderen Systemen) die Performance deutlich verbessern. Statt einzelner FETCHs werden mehrere Zeilen auf einmal geholt:
DECLARE
TYPE emp_table IS TABLE OF employees%ROWTYPE;
l_employees emp_table;
CURSOR emp_cursor IS SELECT * FROM employees;
BEGIN
OPEN emp_cursor;
LOOP
-- 100 Zeilen auf einmal holen
FETCH emp_cursor BULK COLLECT INTO l_employees LIMIT 100;
EXIT WHEN emp_cursor%NOTFOUND;
-- Verarbeitung der 100 Zeilen
FOR i IN 1..l_employees.COUNT LOOP
-- Geschaeftslogik hier
NULL;
END LOOP;
END LOOP;
CLOSE emp_cursor;
END;
BULK COLLECT kann die Performance um den Faktor 3–5 verbessern, indem es die Anzahl der Kontextwechsel reduziert.
Wann solltest du Cursor verwenden?
Trotz der Performance-Nachteile gibt es legitime Anwendungsfälle für Cursor:
- Komplexe zeilenweise Logik: Wenn jede Zeile unterschiedlich behandelt werden muss und dies nicht in SQL ausdrückbar ist
- Externe Aufrufe: Wenn für jeden Datensatz ein externes System aufgerufen werden muss (z.B. API-Calls)
- Schrittweise Commits: Bei sehr großen Datenmengen, um Transaktions-Logs nicht zu überlasten
- Debugging und Protokollierung: Wenn der Verarbeitungsfortschritt nachverfolgt werden soll
- Administrative Aufgaben: Wie im Backup-Beispiel, wo für jede Datenbank ein separater Befehl nötig ist
Cursor in verschiedenen Datenbanksystemen
Die grundlegende Funktionsweise von Cursorn ist ähnlich, aber jedes Datenbanksystem hat seine Besonderheiten:
| Datenbanksystem | Besonderheiten |
|---|---|
| SQL Server | Volle Unterstützung aller Cursor-Typen, @@FETCH_STATUS für Statusabfrage |
| Oracle | Cursor FOR Loop, BULK COLLECT, implizite Cursor für SELECT INTO |
| PostgreSQL | Cursor via refcursor-Variablen in PL/pgSQL |
| MySQL | Nur in Stored Procedures, nur Forward-Only, Read-Only |
MySQL hat die stärksten Einschränkungen: Cursor funktionieren nur in Stored Procedures, sind nicht scrollbar und erlauben keine Datenmodifikation. Für komplexere Anforderungen musst du hier oft auf Anwendungslogik ausweichen.
Cursor in der IHK-Prüfung
Für die Abschlussprüfung zum Fachinformatiker solltest du folgende Punkte beherrschen:
- Die fünf Phasen des Cursor-Lebenszyklus (DECLARE, OPEN, FETCH, CLOSE, DEALLOCATE)
- Die Unterschiede zwischen Forward-Only, Static, Dynamic und Keyset-Driven Cursorn
- Wann Cursor sinnvoll sind und wann mengenbasierte Operationen bevorzugt werden sollten
- Grundlegende Syntax in mindestens einem SQL-Dialekt (meist T-SQL oder PL/SQL)
- Das Konzept des Impedance Mismatch zwischen SQL und prozeduralen Sprachen
Quellen und weiterführende Links
- Microsoft Learn: Cursor in SQL Server - Offizielle Microsoft-Dokumentation
- Oracle: Working with Cursors - Best Practices für Oracle PL/SQL
- MySQL: Cursors - MySQL-Dokumentation
- PostgreSQL: PL/pgSQL Cursors - PostgreSQL-Handbuch
- Wikipedia: Cursor (databases) - Allgemeine Übersicht
Prüfungsbezug
Passt zu deiner Prüfungsvorbereitung
Wenn dir dieser Begriff in Aufgaben, Projektdokumentation oder Fachgespräch begegnet, ordne ihn direkt in den Prüfungsstoff ein.