Тази статия описва SQL курсорите и как да ги използвате за някои специални цели. Той подчертава важността на SQL курсорите заедно с техните недостатъци.
Не винаги е така, че използвате SQL курсора в програмирането на база данни, но тяхното концептуално разбиране и научаване как да ги използвате помагат много да разберете как да изпълнявате изключителни задачи в програмирането на T-SQL.
Общ преглед на SQL курсорите
Нека преминем през някои основи на SQL курсорите, ако не сте запознати с тях.
Проста дефиниция
SQL курсорът предоставя достъп до данни един ред в даден момент, като по този начин ви дава повече (ред по ред) контрол върху набора от резултати.
Определение на Microsoft
Според документацията на Microsoft, операторите на Microsoft SQL Server дават пълен набор от резултати, но има моменти, когато резултатите се обработват най-добре един ред по ред. Отварянето на курсор върху набор от резултати позволява обработка на набора от резултати един ред по ред.
T-SQL и набор от резултати
Тъй като и в простите, и в дефинициите на Microsoft за SQL курсора се споменава набор от резултати, нека се опитаме да разберем какъв точно е резултатният набор в контекста на програмирането на база данни. Нека бързо създадем и попълним таблицата Students в примерна база данни UniversityV3, както следва:
CREATE TABLE [dbo].[Студент] ( [StudentId] INT IDENTITY (1, 1) NOT NULL, [Име] VARCHAR (30) NULL, [Course] VARCHAR (30) NULL, [Marks] INT NULL, [ExamDate] DATETIME2 (7) NULL, CONSTRAINT [PK_Student] ПЪРВИЧЕН КЛУСТЕР ([StudentId] ASC));-- (5) Попълване на таблица на студентаSET IDENTITY_INSERT [dbo].[Студент] ONINSERT INTO [dbo].[Студент] (Студент) ( [StudentId], [Име], [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]) STORYS (3, N') Sam', N'Система за управление на бази данни', 85, N'2016-01-01 00:00:00')INSERT INTO [dbo].[Student] ([StudentId], [Име], [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')ЗАДАДЕТЕ IDENTITY_INSERT [dbo].[Студент] ИЗКЛ.
Сега изберете всички редове от Ученик таблица:
-- Преглед на данните от таблицата на студентите SELECT [StudentId], [Име], [Course], [Marks], [ExamDate] FROM dbo.Student
Това е наборът от резултати, който се връща в резултат на избор на всички записи от Студент таблица.
T-SQL и теория на множеството
T-SQL се основава изцяло на следните две математически концепции:
- Теория на множеството
- Предикатна логика
Теорията на множествата, както показва името, е клон на математиката за множествата, които също могат да бъдат наречени колекции от определени отделни обекти.
Накратко, в теорията на множествата ние мислим за нещата или обектите като цяло по същия начин, по който мислим за отделен елемент.
Например ученикът е набор от всички определени отделни ученици, така че вземаме ученик като цяло, което е достатъчно, за да получим подробности за всички ученици в този набор (таблица).
Моля, вижте моята статия Изкуството на агрегирането на данни в SQL от прости към плъзгащи се агрегации за повече подробности.
Курсори и операции, базирани на редове
T-SQL е предназначен предимно за извършване на операции, базирани на набор, като избиране на всички записи от таблица или изтриване на всички редове от таблица.
Накратко, T-SQL е специално проектиран да работи с таблици по набор, базиран на начин, което означава, че мислим за таблица като цяло и всяка операция като избор, актуализиране или изтриване се прилага като цяло към таблицата или определени редове, които отговарят на критериите.
Въпреки това, има случаи, когато таблиците трябва да бъдат достъпни ред по ред, а не като един единствен набор от резултати, и това е, когато курсорите влизат в действие.
Според Vaidehi Pandere понякога логиката на приложението трябва да работи с един ред в даден момент, а не с всички редове наведнъж, което е същото като цикъл (използване на цикли за повторение) през целия набор от резултати.
Основи на SQL курсорите с примери
Нека сега да обсъдим повече за SQL курсорите.
Първо, нека научим или прегледаме (тези, които вече са запознати с използването на курсори в T-SQL) как да използваме курсора в T-SQL.
Използването на SQL курсора е процес от пет стъпки, изразен по следния начин:
- Деклариране на курсора
- Отворете курсора
- Извличане на редове
- Затворете курсора
- Освобождаване на курсора
Стъпка 1:Деклариране на курсора
Първата стъпка е да декларирате SQL курсора, така че да може да се използва след това.
SQL курсорът може да бъде деклариран, както следва:
DECLARE Cursorза
Стъпка 2:Отворете курсора
Следващата стъпка след декларацията е да отворите курсора, което означава попълване на курсора с набора от резултати, който се изразява по следния начин:
Отворете
Стъпка 3:Извличане на редове
След като курсорът е деклариран и отворен, следващата стъпка е да започнете да извличате редове от SQL курсора един по един, така че извличащите редове да получат следващия наличен ред от SQL курсора:
Извличане на следващо от
Стъпка 4:Затворете курсора
След като редовете бъдат извлечени един по един и манипулирани според изискването, следващата стъпка е да затворите SQL курсора.
Затварянето на SQL курсора изпълнява три задачи:
- Освобождава набора от резултати, който в момента се държи от курсора
- Освобождава всички заключвания на курсора върху редовете от курсора
- Затваря отворения курсор
Простият синтаксис за затваряне на курсора е както следва:
Затворете
Стъпка 5:Освобождаване на курсора
Последната стъпка в това отношение е да освободите курсора, което премахва препратката към курсора.
Синтаксисът е следният:
DEALLOCATE
Съвместимост на SQL курсора
Според документацията на Microsoft SQL курсорите са съвместими със следните версии:
- SQL Server 2008 и по-нови версии
- Azure SQL база данни
Пример 1 на SQL курсора:
Сега, когато сме запознати със стъпките за внедряване на SQL курсора, нека разгледаме прост пример за използване на SQL курсора:
-- Пример за деклариране на курсор на студент 1USE UniversityV3GODECLARE Student_Cursor CURSOR FOR SELECT StudentId ,[Name]FROM dbo.Student;OPEN Student_CursorFETCH NEXT FROM Student_CursorWHILE @@FETCH_STATUS =0BEGINFETCH Student_Cursor CURSOR FOR SELECT StudentId ,[Name]FROM dbo.Student;OPEN Student_CursorFETCH NEXT FROM Student_CursorWHILE @@FETCH_STATUS =0BEGINFETCH Student_Cursor NEXCATE FROM.Резултатът е както следва:
Пример 2 на SQL курсора:
В този пример ще използваме две променливи, за да съхраняваме данните, държани от курсора, докато се движи от ред на ред, така че да можем да показваме набора от резултати един ред наведнъж, като показваме стойностите на променливите.
-- Деклариране на курсора на студент с пример за променливи 2USE UniversityV3GODECLARE @StudentId INT ,@StudentName VARCHAR(40) -- Деклариране на променливи за задържане на данни за ред, съхранявани от cursorDECLARE Student_Cursor CURSOR FOR SELECT StudentId ,[Име]FROM dbo Student_Student.FROMENCHCurs; NEXT FROM Student_Cursor INTO @StudentId, @StudentName -- Извличане на първия ред и съхраняването му в променливиWHILE @@FETCH_STATUS =0BEGINPRINT CONCAT(@StudentId,'--', @StudentName) -- Показване на данни за променливитеFETCH NEXT FROM Student_Cursor -- Вземете следващия ред данни в курсора и ги съхранявайте в променливиINTO @StudentId, @StudentNameENDCLOSE Student_Cursor -- Затворете заключванията на курсора по редоветеDEALLOCATE Student_Cursor -- Освободете препратка към курсораРезултатът от горния SQL код е както следва:
Някой би могъл да твърди, че можем да постигнем същия изход, като използваме прост SQL скрипт, както следва:
-- Преглед на идентификатора и името на ученика без SQL курсорSELECT StudentId,Name FROM dbo.Studentorder от StudentId
Всъщност има доста задачи, които изискват използването на SQL курсори, въпреки факта, че не се препоръчва използването на SQL курсори поради прякото им въздействие върху паметта.
Важна забележка
Моля, имайте предвид, че според Vaidehi Pandere, курсорите са резидентен набор от указатели, така че те заемат вашата системна памет, която иначе би се използвала от други важни процеси; ето защо преминаването на голям набор от резултати чрез курсори никога не е добра идея, освен ако няма основателна причина за това.
Използване на SQL курсори за специални цели
Ще преминем през някои специални цели, за които могат да се използват SQL курсори.
Тестване на паметта на сървъра на базата данни
Тъй като SQL курсорите имат силно въздействие върху системната памет, те са добри кандидати за възпроизвеждане на сценарии, при които прекомерното използване на паметта от различни съхранени процедури или ad-hoc SQL скриптове трябва да бъде проучено.
Един лесен начин да разберете това е да щракнете върху бутона за статистика на клиента в лентата с инструменти (или натиснете Shift+Alt+S) в SSMS (SQL Server Management Studio) и да изпълните проста заявка без курсор:
Сега изпълнете заявката с курсора, като използвате променливи (пример на SQL курсор 2):
Сега, моля, отбележете разликите:
Брой изрази SELECT без курсор:1
Брой изрази SELECT с курсор:7
Брой връщане на сървъра без курсора:1
Брой връщане на сървъра с курсора:2
Време за обработка на клиента без курсора:1
Време за обработка на клиента с курсора:8
Общо време за изпълнение без курсора:1
Общо време за изпълнение с курсора:38
Време за изчакване на отговорите на сървъра без курсор:0
Време за изчакване на отговорите на сървъра с курсора:30
Накратко, изпълнението на заявката без курсора, който връща само 5 реда, изпълнява същата заявка 6-7 пъти с курсора.
Сега можете да си представите колко лесно е да възпроизведете въздействието върху паметта с помощта на курсори, но това не винаги е най-доброто, което можете да направите.
Задачи за манипулиране на групови обекти на база данни
Има още една област, където SQL курсорите могат да бъдат удобни и това е, когато трябва да извършим групова операция върху бази данни или обекти на база данни.
За да разберем това, първо трябва да създадем таблицата на курса и да я попълним в UniversityV3 база данни, както следва:
-- Създаване на таблица на курса CREATE TABLE [dbo].[Course] ( [CourseId] INT IDENTITY (1, 1) NOT NULL, [Име] VARCHAR (30) NOT NULL, [Подробности] VARCHAR (200) NULL, CONSTRAINT [PK_Course] PRIMARY KEY CLUSTERED ([CourseId] ASC));-- Попълване на таблица на курс SET IDENTITY_INSERT [dbo].[Курс] ONINSERT INTO [dbo].[Course] ([CourseId], [Име], [Подробности]) VALUES (1, N'DevOps за бази данни', N'Става въпрос за DevOps за бази данни')ВМЪКНЕТЕ В [dbo].[Курс] ([CourseId], [Име], [Подробности]) СТОЙНОСТИ (2, N'Power BI). Fundamentals', N'Става въпрос за Power BI Fundamentals')INSERT INTO [dbo].[Course] ([CourseId], [Name], [Detail]) VALUES (3, N'T-SQL Programming', N'About). Програмиране с T-SQL')INSERT INTO [dbo].[Course] ([CourseId], [Name], [Detail]) VALUES (4, N'Таблично моделиране на данни', N'Това е за таблично моделиране на данни')INSERT. INTO [dbo].[Course] ([CourseId], [Name], [Detail]) VALUES (5, N'Analysis Services Fundamentals', N'Това е за Analysis Services Fundamentals')SET IDENTITY_INSERT'). [dbo].[Курс] ИЗКЛ.Да предположим, че искаме да преименуваме всички съществуващи таблици в UniversityV3 база данни като СТАРИ таблици.
Това изисква итерация на курсора върху всички таблици една по една, за да могат да бъдат преименувани.
Следният код върши работа:
-- Декларирайте курсора на студента, за да преименувате всички таблици като oldUSE UniversityV3GODECLARE @TableName VARCHAR(50) -- Име на съществуваща таблица ,@NewTableName VARCHAR(50) -- Ново име на таблицаDECLARE Student_Cursor CURSOR FOR SELECT T.TABLE_NAME_SCHEMA SELECT T;OPEN Student_CursorFETCH NEXT FROM Student_Cursor INTO @TableNameWHILE @@FETCH_STATUS =0BEGINSET @[email protected]+'_OLD' -- Добавете _OLD към съществуващото име на таблицатаEXEC sp_rename @TableName,@NewTableName,@NewTableName,@NewTableName,@NewTableName,@FETCH_STATUS =0 -- Вземете данните от следващия ред в курсора и ги съхранете в променливиINTO @TableNameENDCLOSE Student_Cursor -- Затворете заключванията на курсора на редоветеDEALLOCATE Student_Cursor -- Освободете препратка към курсора
Поздравления, успешно преименувахте всички съществуващи таблици с помощта на SQL курсора.
Неща за правене
След като вече сте запознати с използването на SQL курсора, моля, опитайте следните неща:
- Моля, опитайте да създадете и преименувате индекси на всички таблици на примерна база данни чрез курсора.
- Моля, опитайте да върнете преименуваните таблици в тази статия обратно към оригиналните имена с помощта на курсора.
- Моля, опитайте да попълните таблици с много редове и измерете статистиката и времето за заявките със и без курсора.