sql >> Database teknologi >  >> RDS >> Database

Udskiftning af SQL-markører med alternativer for at undgå præstationsproblemer

I denne artikel vil vi se på nogle alternativer til at bruge SQL-markører, som kan hjælpe med at undgå ydeevneproblemer forårsaget af brug af markører.

Før vi diskuterer alternativerne, lad os gennemgå det generelle koncept for SQL-markører.

Hurtig oversigt over SQL-markører

SQL-markører bruges primært, hvor sæt-baserede operationer ikke er anvendelige, og du er forpligtet til at få adgang til data og udføre operationer én række ad gangen i stedet for at anvende en enkelt sæt-baseret operation på et helt objekt (såsom en tabel eller et sæt af tabeller).

Simpel definition

En SQL-markør giver adgang til data én række ad gangen og giver dig derved direkte række-for-række kontrol over resultatsættet.

Microsoft Definition

Ifølge Microsofts dokumentation producerer Microsoft SQL Server-sætninger et komplet resultatsæt, men der er tidspunkter, hvor det er bedst at behandle det én række ad gangen – hvilket kan gøres ved at åbne en markør på resultatsættet.

5-trins processen med at bruge en markør

Processen med at bruge en SQL-markør kan generelt beskrives som følger:

  1. Erklær markør
  2. Åbn markør
  3. Hent rækker
  4. Luk markør
  5. Deallokér markør

Vigtig bemærkning

Vær venligst opmærksom på, at ifølge Vaidehi Pandere er markører pointere, der optager din systemhukommelse – som ellers ville være reserveret til andre vigtige processer. Derfor er det normalt ikke den bedste idé at krydse et stort resultatsæt ved at bruge markører – medmindre der er en legitim grund til at gøre det.

For mere detaljeret information om dette, er du velkommen til at henvise til min artikel Sådan bruger du SQL-markører til særlige formål.

SQL-markøreksempel

Først vil vi se på et eksempel på, hvordan en SQL-markør kan bruges til at omdøbe databaseobjekter én efter én.

For at oprette en SQL-markør, vi har brug for, lad os opsætte en prøvedatabase, så vi kan køre vores scripts mod den.

Opsætning af prøvedatabase (UniversityV3)

Kør følgende script for at oprette og udfylde UniversityV3-eksempeldatabasen med to tabeller:

-- (1) Create UniversityV3 sample database

CREATE DATABASE UniversityV3;

GO

USE UniversityV3

-- (2) Create Course table

IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES T WHERE T.TABLE_NAME='Course') 

DROP TABLE dbo.Course 

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)

);

-- (3) Create Student table

IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES T WHERE T.TABLE_NAME='Student') 

DROP TABLE dbo.Student 

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)

);

-- (4) 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



-- (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

Opret en SQL-markør for at omdøbe tabeller (_Backup)

Overvej nu at opfylde følgende specifikation ved at bruge en markør:

  1. Vi skal tilføje '_Backup' til navnene på alle eksisterende tabeller i en database
  2. Tabeller, der allerede har '_Backup' i deres navn, bør ikke omdøbes

Lad os oprette en SQL-markør for at omdøbe alle tabeller i eksempeldatabasen ved at tilføje '_Backup' til hver tabels navn, samtidig med at vi sikrer, at tabeller, der indeholder '_Backup' i deres navn, ikke omdøbes igen ved at køre følgende kode:

-- Declaring the Student cursor to rename all tables by adding ‘_backup’ to their names and also making sure that all tables that are already named correctly will be skipped:

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

IF RIGHT(@TableName,6)<>'Backup' -- If Backup table does not exist then rename the table

BEGIN

SET @[email protected]+'_Backup' -- Add _Backup to the table’s current name

EXEC sp_rename @TableName,@NewTableName -- Rename table as OLD table

END

ELSE

PRINT 'Backup table name already exists: '[email protected]

FETCH NEXT FROM Student_Cursor -- Get next row data into cursor and store it in variables

INTO @TableName

END

CLOSE Student_Cursor -- Close cursor locks on the rows

DEALLOCATE Student_Cursor -- Release cursor reference

Kør omdøbningsscriptet og se resultater

Tryk nu på F5 i SSMS (SQL Server Management Studio) for at køre scriptet og se resultaterne:

Opdatering af tabellernes navne i SSMS-objektudforskeren viser tydeligt, at vi har ændret dem som specificeret.

Lad os køre scriptet igen ved at trykke på F5 igen og se på resultaterne:

Oprettelse af en SQL-markør for at nulstille _Backup-navngivning

Vi skal også oprette et script, der bruger en SQL-markør til at vende navnene på de tabeller, vi lige har ændret, tilbage til de oprindelige - vi gør dette ved at fjerne '_Backup' fra deres navne.

Scriptet nedenfor vil lade os gøre netop det :

-- Declare the Student cursor to reset tables names _backup to their original forms by removing ‘_backup’

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

IF RIGHT(@TableName,6)='Backup' -- If Backup table name exists then reset (rename) it

BEGIN

SET @NewTableName=SUBSTRING(@TableName,1,LEN(@TableName)-7) -- Remove _Backup from the table name

EXEC sp_rename @TableName,@NewTableName -- Rename table 

END

ELSE

PRINT 'Backup table name already reset: '[email protected]

FETCH NEXT FROM Student_Cursor – Get the data of the next row into cursor and store it in variables

INTO @TableName

END

CLOSE Student_Cursor -- Close cursor locks on the rows

DEALLOCATE Student_Cursor -- Release cursor reference

Kør Nulstil scriptet og se resultater

Kørsel af scriptet viser, at tabelnavne er blevet nulstillet:

Dette var eksempler på nogle scenarier, hvor det er svært at undgå at bruge SQL-markører på grund af kravets karakter. Det er dog stadig muligt at finde en alternativ tilgang.

SQL-markøralternativer

Der er to mest almindelige alternativer til SQL-markører, så lad os se nærmere på hver enkelt af dem.

Alternativ 1:Tabelvariable

Et af disse alternativer er tabelvariabler.

Tabelvariabler kan ligesom tabeller gemme flere resultater - men med en vis begrænsning. Ifølge Microsoft-dokumentationen er en tabelvariabel en speciel datatype, der bruges til at gemme et resultatsæt til behandling på et senere tidspunkt.

Husk dog, at tabelvariabler bedst bruges med små datasæt.

Tabelvariabler kan være meget effektive til forespørgsler i lille skala, da de fungerer som lokale variabler og ryddes op automatisk, når de kommer uden for scope.

Tabelvariabelstrategi:

Vi vil bruge tabelvariabler i stedet for SQL-markører til at omdøbe alle tabeller fra en database ved at følge disse trin:

  1. Deklarer en tabelvariabel
  2. Gem tabelnavne og id'er i den tabelvariabel, vi har erklæret
  3. Sæt tælleren til 1 og få det samlede antal poster fra tabelvariablen
  4. Brug en "mens"-løkke, så længe tælleren er mindre end eller lig med det samlede antal poster
  5. Inde i 'mens'-løkken omdøber vi tabeller én efter én, så længe de ikke allerede er omdøbt og øger tælleren for hver tabel

Tabelvariabelkode:

Kør følgende SQL-script, som opretter og bruger en tabelvariabel til at omdøbe tabeller:

-- Declare Student Table Variable to rename all tables by adding ‘_backup’ t their name and also making sure that already renamed tables are skipped

USE UniversityV3

GO

DECLARE @TableName VARCHAR(50) -- Existing table name
       ,@NewTableName VARCHAR(50) -- New table name

DECLARE @StudentTableVar TABLE -- Declaring a table variable to store tables names
(
TableId INT,

TableName VARCHAR(40))

INSERT INTO @StudentTableVar -- insert tables names into the table variable 

SELECT ROW_NUMBER() OVER(ORDER BY T.TABLE_NAME),T.TABLE_NAME FROM INFORMATION_SCHEMA.TABLES T

DECLARE @TotalRows INT=(SELECT COUNT(*) FROM @StudentTableVar),@i INT=1 -- Get total rows and set counter to 1

WHILE @i<[email protected] -- begin as long as i (counter) is less than or equal to the total number of records

BEGIN -- ‘While’ loop begins here

SELECT @TableName=TableName from @StudentTableVar WHERE [email protected]

IF RIGHT(@TableName,6)<>'Backup' -- If a Backup table does not exist, then rename the table

BEGIN

SET @[email protected]+'_Backup' -- Add _Backup to the table’s current name

EXEC sp_rename @TableName,@NewTableName -- Rename the table as OLD table

END

ELSE

PRINT 'Backup table name already exists: '[email protected]

SET @[email protected]+1

END -- 'While' loop ends here

Kør scriptet og se resultater

Lad os nu udføre scriptet og kontrollere resultaterne:

Alternativ 2:Midlertidige tabeller

Vi kan også bruge midlertidige tabeller i stedet for SQL-markører til at gentage resultatsættet en række ad gangen.

Midlertidige tabeller har været i brug i lang tid og er en fremragende måde at erstatte markører på for store datasæt.

Ligesom tabelvariabler kan midlertidige tabeller holde resultatsættet, så vi kan udføre de nødvendige operationer ved at behandle det med en itererende algoritme såsom en 'mens'-løkke.

Midlertidig tabelstrategi:

Vi vil bruge en midlertidig tabel til at omdøbe alle tabeller i eksempeldatabasen ved at følge disse trin:

  1. Deklarer en midlertidig tabel
  2. Gem tabelnavne og id'er i den midlertidige tabel, vi lige har erklæret
  3. Sæt tælleren til 1 og få det samlede antal poster fra den midlertidige tabel
  4. Brug en "mens"-løkke, så længe tælleren er mindre end eller lig med det samlede antal poster
  5. Inden for "mens"-løkken skal du omdøbe tabeller én efter én, så længe de ikke allerede er omdøbt, og øge tælleren for hver tabel

Nulstil tabellerne

Vi skal nulstille tabellernes navne til deres oprindelige form ved at slette '_Backup' fra slutningen af ​​deres navne, så kør venligst det nulstillingsscript, vi allerede har skrevet og brugt ovenfor, så vi kan anvende en anden metode til at omdøbe tabeller.

Midlertidig tabelkode:

Kør følgende SQL-script for at oprette og bruge en midlertidig tabel til at omdøbe alle tabeller i vores database:

-- Declare the Student Temporary Table to rename all tables by adding ‘_backup’ to their names while also making sure that already renamed tables are skipped

USE UniversityV3

GO

DECLARE @TableName VARCHAR(50) -- Existing table name
       ,@NewTableName VARCHAR(50) -- New table name

CREATE TABLE #Student -- Declaring a temporary table

(
TableId INT,
TableName VARCHAR(40)
)

INSERT INTO #Student -- insert tables names into the temporary table

SELECT ROW_NUMBER() OVER(ORDER BY T.TABLE_NAME),T.TABLE_NAME FROM INFORMATION_SCHEMA.TABLES T

DECLARE @TotalRows INT=(SELECT COUNT(*) FROM #Student),@i INT=1 -- Get the total amount of rows and set the counter to 1

WHILE @i<[email protected] -- begin as long as i (counter) is less than or equal to the total number of records

BEGIN -- ‘While’ loop begins here

SELECT @TableName=TableName from #Student WHERE [email protected]

IF RIGHT(@TableName,6)<>'Backup' -- If a Backup table does not exist, then rename the table

BEGIN

SET @[email protected]+'_Backup' -- Add ‘_Backup’ to the table’s current name

EXEC sp_rename @TableName,@NewTableName -- Rename the table as OLD table

END

ELSE

PRINT 'Backup table name already exists: '[email protected]

SET @[email protected]+1

END -- While loop ends here

DROP TABLE #Student

Kør scriptet og tjek outputtet

Lad os nu udføre scriptet for at se resultaterne:

Ting at gøre

Nu hvor du er bekendt med alternativer til SQL-markører – såsom brug af tabelvariabler og midlertidige tabeller – prøv venligst at gøre følgende for at blive fortrolig med at anvende denne viden i praksis:

  1. Opret og omdøb indekser for alle tabeller i en eksempeldatabase – først via en markør og derefter ved at bruge alternative metoder (tabelvariabler og midlertidige tabeller)
  2. Gendan navnene på tabellerne fra denne artikel tilbage til deres oprindelige navne ved hjælp af alternative metoder (midlertidige tabeller og tabelvariabler)
  3. Du kan også henvise til de første eksempler i min artikel Sådan bruger du SQL-markører til specielle formål og prøv at udfylde tabeller med masser af rækker og måle statistikken og tiden for forespørgslerne for at sammenligne den grundlæggende markørmetode med alternativerne

  1. Batch-tilstand normalisering og ydeevne

  2. Sådan tilføjes en logfil til en SQL Server-database (T-SQL)

  3. Kontrollerer, om et element ikke findes i en anden tabel

  4. Postgres:hvordan runder du et tidsstempel op eller ned til nærmeste minut?