Dieser Artikel beschreibt SQL-Cursor und ihre Verwendung für einige spezielle Zwecke. Es hebt die Bedeutung von SQL-Cursorn zusammen mit ihren Nachteilen hervor.
Es ist nicht immer der Fall, dass Sie SQL-Cursor in der Datenbankprogrammierung verwenden, aber ihr konzeptionelles Verständnis und das Erlernen ihrer Verwendung hilft sehr dabei, zu verstehen, wie man außergewöhnliche Aufgaben in der T-SQL-Programmierung ausführt.
SQL-Cursor-Übersicht
Lassen Sie uns einige Grundlagen von SQL-Cursor durchgehen, wenn Sie damit nicht vertraut sind.
Einfache Definition
Ein SQL-Cursor bietet zeilenweise Zugriff auf Daten, wodurch Sie (zeilenweise) mehr Kontrolle über die Ergebnismenge haben.
Microsoft-Definition
Gemäß der Microsoft-Dokumentation erzeugen Microsoft SQL Server-Anweisungen eine vollständige Ergebnismenge, aber es gibt Zeiten, in denen die Ergebnisse am besten zeilenweise verarbeitet werden. Das Öffnen eines Cursors auf einer Ergebnismenge ermöglicht die zeilenweise Verarbeitung der Ergebnismenge.
T-SQL und Ergebnismenge
Da sowohl eine einfache als auch eine Microsoft-Definition des SQL-Cursors eine Ergebnismenge erwähnen, versuchen wir zu verstehen, was genau die Ergebnismenge im Kontext der Datenbankprogrammierung ist. Lassen Sie uns schnell die Tabelle Students in einer Beispieldatenbank UniversityV3 wie folgt erstellen und füllen:
CREATE TABLE [dbo].[Student] ( [StudentId] INT IDENTITY (1, 1) NOT NULL, [Name] VARCHAR (30) NULL, [Course] VARCHAR (30) NULL, [Marks] INT NULL, [ExamDate] DATETIME2 (7) NULL, CONSTRAINT [PK_Student] PRIMARY KEY CLUSTERED ([StudentId] ASC) ); -- (5) Populate Student table SET IDENTITY_INSERT [dbo].[Student] ON INSERT INTO [dbo].[Student] ([StudentId], [Name], [Course], [Marks], [ExamDate]) VALUES (1, N'Asif', N'Database Management System', 80, N'2016-01-01 00:00:00') INSERT INTO [dbo].[Student] ([StudentId], [Name], [Course], [Marks], [ExamDate]) VALUES (2, N'Peter', N'Database Management System', 85, N'2016-01-01 00:00:00') INSERT INTO [dbo].[Student] ([StudentId], [Name], [Course], [Marks], [ExamDate]) VALUES (3, N'Sam', N'Database Management System', 85, N'2016-01-01 00:00:00') INSERT INTO [dbo].[Student] ([StudentId], [Name], [Course], [Marks], [ExamDate]) VALUES (4, N'Adil', N'Database Management System', 85, N'2016-01-01 00:00:00') INSERT INTO [dbo].[Student] ([StudentId], [Name], [Course], [Marks], [ExamDate]) VALUES (5, N'Naveed', N'Database Management System', 90, N'2016-01-01 00:00:00') SET IDENTITY_INSERT [dbo].[Student] OFF
Wählen Sie nun alle Zeilen von Schüler aus Tabelle:
-- View Student table data SELECT [StudentId], [Name], [Course], [Marks], [ExamDate] FROM dbo.Student
Dies ist die Ergebnismenge, die als Ergebnis der Auswahl aller Datensätze aus Student zurückgegeben wird Tabelle.
T-SQL und Mengenlehre
T-SQL basiert ausschließlich auf den folgenden zwei mathematischen Konzepten:
- Mengentheorie
- Prädikatenlogik
Die Mengenlehre ist, wie der Name schon sagt, ein Teilgebiet der Mathematik über Mengen, die auch als Sammlungen bestimmter Objekte bezeichnet werden können.
Kurz gesagt, in der Mengenlehre denken wir an Dinge oder Objekte als Ganzes, genauso wie wir an einen einzelnen Gegenstand denken.
Zum Beispiel ist der Schüler eine Menge aller eindeutig unterschiedlichen Schüler, also nehmen wir einen Schüler als Ganzes, was ausreicht, um Details aller Schüler in dieser Menge (Tabelle) zu erhalten.
Weitere Einzelheiten finden Sie in meinem Artikel The Art of Aggregating Data in SQL from Simple to Sliding Aggregations.
Cursor und zeilenbasierte Operationen
T-SQL wurde hauptsächlich entwickelt, um mengenbasierte Operationen auszuführen, wie z. B. das Auswählen aller Datensätze aus einer Tabelle oder das Löschen aller Zeilen aus einer Tabelle.
Kurz gesagt, T-SQL wurde speziell entwickelt, um mit Tabellen satzbasiert zu arbeiten, was bedeutet, dass wir uns eine Tabelle als Ganzes vorstellen und jede Operation wie Auswählen, Aktualisieren oder Löschen als Ganzes oder als Ganzes auf die Tabelle angewendet wird Zeilen, die die Kriterien erfüllen.
Es gibt jedoch Fälle, in denen auf Tabellen Zeile für Zeile und nicht auf eine einzelne Ergebnismenge zugegriffen werden muss, und hier kommen Cursor zum Einsatz.
Laut Vaidehi Pandere muss die Anwendungslogik manchmal mit einer Zeile nach der anderen arbeiten und nicht mit allen Zeilen auf einmal, was dasselbe ist wie eine Schleife (Verwendung von Schleifen zum Durchlaufen) durch die gesamte Ergebnismenge.
Grundlagen von SQL-Cursor mit Beispielen
Lassen Sie uns nun mehr über SQL-Cursor diskutieren.
Lassen Sie uns zunächst lernen oder wiederholen (diejenigen, die bereits mit der Verwendung von Cursorn in T-SQL vertraut sind), wie Cursor in T-SQL verwendet werden.
Die Verwendung des SQL-Cursors ist ein fünfstufiger Prozess, der wie folgt ausgedrückt wird:
- Cursor deklarieren
- Cursor öffnen
- Zeilen abrufen
- Cursor schließen
- Zuweisung des Cursors aufheben
Schritt 1:Cursor deklarieren
Der erste Schritt besteht darin, den SQL-Cursor zu deklarieren, damit er später verwendet werden kann.
SQL-Cursor kann wie folgt deklariert werden:
DECLARE Cursor <Cursor_Name> for <SQL statement>
Schritt 2:Cursor öffnen
Der nächste Schritt nach der Deklaration besteht darin, den Cursor zu öffnen, was bedeutet, dass der Cursor mit der Ergebnismenge gefüllt wird, die wie folgt ausgedrückt wird:
Open <Cursor_Name>
Schritt 3:Zeilen abrufen
Nachdem der Cursor deklariert und geöffnet wurde, besteht der nächste Schritt darin, Zeilen nacheinander vom SQL-Cursor abzurufen, damit beim Abrufen von Zeilen die nächste verfügbare Zeile vom SQL-Cursor abgerufen wird:
Fetch Next from <Cursor_Name>
Schritt 4:Cursor schließen
Sobald die Zeilen einzeln abgerufen und gemäß den Anforderungen bearbeitet wurden, besteht der nächste Schritt darin, den SQL-Cursor zu schließen.
Das Schließen des SQL-Cursors führt drei Aufgaben aus:
- Gibt die aktuell vom Cursor gehaltene Ergebnismenge frei
- Hebt alle Cursorsperren auf den Zeilen durch den Cursor auf
- Schließt den geöffneten Cursor
Die einfache Syntax zum Schließen des Cursors lautet wie folgt:
Close <Cursor_Name>
Schritt 5:Cursor aufheben
Der letzte Schritt in dieser Hinsicht besteht darin, den Cursor freizugeben, wodurch die Cursorreferenz entfernt wird.
Die Syntax lautet wie folgt:
DEALLOCATE <Cursor_Name>
SQL-Cursor-Kompatibilität
Laut Microsoft-Dokumentation sind SQL-Cursor mit den folgenden Versionen kompatibel:
- Versionen von SQL Server 2008 und höher
- Azure SQL-Datenbank
SQL-Cursor Beispiel 1:
Nachdem wir nun mit den Schritten zur Implementierung des SQL-Cursors vertraut sind, wollen wir uns ein einfaches Beispiel für die Verwendung des SQL-Cursors ansehen:
-- Declare Student cursor example 1 USE UniversityV3 GO DECLARE Student_Cursor CURSOR FOR SELECT StudentId ,[Name] FROM dbo.Student; OPEN Student_Cursor FETCH NEXT FROM Student_Cursor WHILE @@FETCH_STATUS = 0 BEGIN FETCH NEXT FROM Student_Cursor END CLOSE Student_Cursor DEALLOCATE Student_Cursor
Die Ausgabe sieht wie folgt aus:
SQL-Cursor Beispiel 2:
In diesem Beispiel werden wir zwei Variablen verwenden, um die vom Cursor gehaltenen Daten zu speichern, während er sich von Zeile zu Zeile bewegt, sodass wir die Ergebnismenge zeilenweise anzeigen können, indem wir die Variablenwerte anzeigen.
-- Declare Student cursor with variables example 2 USE UniversityV3 GO DECLARE @StudentId INT ,@StudentName VARCHAR(40) -- Declare variables to hold row data held by cursor DECLARE Student_Cursor CURSOR FOR SELECT StudentId ,[Name] FROM dbo.Student; OPEN Student_Cursor FETCH NEXT FROM Student_Cursor INTO @StudentId, @StudentName -- Fetch first row and store it into variables WHILE @@FETCH_STATUS = 0 BEGIN PRINT CONCAT(@StudentId,'--', @StudentName) -- Show variables data FETCH NEXT FROM Student_Cursor -- Get next row data into cursor and store it into variables INTO @StudentId, @StudentName END CLOSE Student_Cursor -- Close cursor locks on the rows DEALLOCATE Student_Cursor -- Release cursor reference
Das Ergebnis des obigen SQL-Codes lautet wie folgt:
Man könnte argumentieren, dass wir die gleiche Ausgabe erreichen können, indem wir ein einfaches SQL-Skript wie folgt verwenden:
-- Viewing student id and name without SQL cursor SELECT StudentId,Name FROM dbo.Student order by StudentId
Tatsächlich gibt es einige Aufgaben, für die SQL-Cursor verwendet werden müssen, obwohl von der Verwendung von SQL-Cursor aufgrund ihrer direkten Auswirkung auf den Speicher abgeraten wird.
Wichtiger Hinweis
Bitte denken Sie daran, dass Cursor laut Vaidehi Pandere ein speicherresidenter Satz von Zeigern sind, sodass sie Ihren Systemspeicher belegen, der sonst von anderen wichtigen Prozessen verwendet würde; Aus diesem Grund ist es nie eine gute Idee, eine große Ergebnismenge mit Cursorn zu durchlaufen, es sei denn, es gibt einen legitimen Grund dafür.
Verwendung von SQL-Cursor für spezielle Zwecke
Wir werden einige spezielle Zwecke durchgehen, für die SQL-Cursor verwendet werden können.
Datenbankserver-Speichertest
Da SQL-Cursor einen großen Einfluss auf den Systemspeicher haben, sind sie gute Kandidaten zum Replizieren von Szenarien, in denen eine übermäßige Speichernutzung durch verschiedene gespeicherte Prozeduren oder Ad-hoc-SQL-Skripts untersucht werden muss.
Eine einfache Möglichkeit, dies zu verstehen, besteht darin, in SSMS (SQL Server Management Studio) auf die Schaltfläche „Client-Statistiken“ in der Symbolleiste zu klicken (oder Umschalt+Alt+S zu drücken) und eine einfache Abfrage ohne Cursor auszuführen:
Führen Sie nun die Abfrage mit dem Cursor mithilfe von Variablen aus (SQL-Cursor-Beispiel 2):
Notieren Sie nun bitte die Unterschiede:
Anzahl der SELECT-Anweisungen ohne Cursor:1
Anzahl der SELECT-Anweisungen mit Cursor:7
Anzahl der Server-Roundtrips ohne Cursor:1
Anzahl Server-Roundtrips mit Cursor:2
Client-Verarbeitungszeit ohne Cursor:1
Client-Verarbeitungszeit mit Cursor:8
Gesamtausführungszeit ohne Cursor:1
Gesamtausführungszeit mit Cursor:38
Wartezeit auf Serverantworten ohne Cursor:0
Wartezeit auf Serverantworten mit Cursor:30
Kurz gesagt, wenn Sie die Abfrage ohne den Cursor ausführen, der nur 5 Zeilen zurückgibt, wird dieselbe Abfrage 6-7 Mal mit dem Cursor ausgeführt.
Jetzt können Sie sich vorstellen, wie einfach es ist, Speicherauswirkungen mit Cursorn zu replizieren, aber das ist nicht immer die beste Vorgehensweise.
Tasks zur Bearbeitung von Massendatenbankobjekten
Es gibt noch einen anderen Bereich, in dem SQL-Cursor nützlich sein können, und zwar dann, wenn wir eine Massenoperation für Datenbanken oder Datenbankobjekte ausführen müssen.
Um dies zu verstehen, müssen wir zuerst die Course-Tabelle erstellen und sie in UniversityV3 füllen Datenbank wie folgt:
-- Create Course table CREATE TABLE [dbo].[Course] ( [CourseId] INT IDENTITY (1, 1) NOT NULL, [Name] VARCHAR (30) NOT NULL, [Detail] VARCHAR (200) NULL, CONSTRAINT [PK_Course] PRIMARY KEY CLUSTERED ([CourseId] ASC) ); -- Populate Course table SET IDENTITY_INSERT [dbo].[Course] ON INSERT INTO [dbo].[Course] ([CourseId], [Name], [Detail]) VALUES (1, N'DevOps for Databases', N'This is about DevOps for Databases') INSERT INTO [dbo].[Course] ([CourseId], [Name], [Detail]) VALUES (2, N'Power BI Fundamentals', N'This is about Power BI Fundamentals') INSERT INTO [dbo].[Course] ([CourseId], [Name], [Detail]) VALUES (3, N'T-SQL Programming', N'About T-SQL Programming') INSERT INTO [dbo].[Course] ([CourseId], [Name], [Detail]) VALUES (4, N'Tabular Data Modeling', N'This is about Tabular Data Modeling') INSERT INTO [dbo].[Course] ([CourseId], [Name], [Detail]) VALUES (5, N'Analysis Services Fundamentals', N'This is about Analysis Services Fundamentals') SET IDENTITY_INSERT [dbo].[Course] OFF
Angenommen, wir möchten alle vorhandenen Tabellen in UniversityV3 umbenennen Datenbank als ALTE Tabellen.
Dies erfordert eine Cursor-Iteration über alle Tabellen, eine nach der anderen, damit sie umbenannt werden können.
Der folgende Code erledigt die Aufgabe:
-- Declare Student cursor to rename all the tables as old USE UniversityV3 GO DECLARE @TableName VARCHAR(50) -- Existing table name ,@NewTableName VARCHAR(50) -- New table name DECLARE Student_Cursor CURSOR FOR SELECT T.TABLE_NAME FROM INFORMATION_SCHEMA.TABLES T; OPEN Student_Cursor FETCH NEXT FROM Student_Cursor INTO @TableName WHILE @@FETCH_STATUS = 0 BEGIN SET @[email protected]+'_OLD' -- Add _OLD to exsiting name of the table EXEC sp_rename @TableName,@NewTableName -- Rename table as OLD table FETCH NEXT FROM Student_Cursor -- Get next row data into cursor and store it into variables INTO @TableName END CLOSE Student_Cursor -- Close cursor locks on the rows DEALLOCATE Student_Cursor -- Release cursor reference
Herzlichen Glückwunsch, Sie haben alle vorhandenen Tabellen erfolgreich mit dem SQL-Cursor umbenannt.
Dinge zu tun
Nachdem Sie nun mit der Verwendung des SQL-Cursors vertraut sind, versuchen Sie bitte Folgendes:
- Bitte versuchen Sie, Indizes aller Tabellen einer Beispieldatenbank mit dem Cursor zu erstellen und umzubenennen.
- Bitte versuchen Sie, die umbenannten Tabellen in diesem Artikel mit dem Cursor wieder auf die ursprünglichen Namen zurückzusetzen.
- Bitte versuchen Sie, Tabellen mit vielen Zeilen zu füllen, und messen Sie die Statistiken und die Zeit für die Abfragen mit und ohne Cursor.