sql >> Databasteknik >  >> RDS >> Database

Byt ut SQL-markörer med alternativ för att undvika prestandaproblem

I den här artikeln kommer vi att titta på några alternativ till att använda SQL-markörer som kan hjälpa till att undvika prestandaproblem som orsakas av att använda markörer.

Innan vi diskuterar alternativen, låt oss se över det allmänna konceptet för SQL-markörer.

Snabb översikt över SQL-markörer

SQL-markörer används främst där uppsättningsbaserade operationer inte är tillämpliga och du måste komma åt data och utföra operationer en rad i taget istället för att tillämpa en enda uppsättningsbaserad operation på ett helt objekt (som en tabell eller en uppsättning av tabeller).

Enkel definition

En SQL-markör ger åtkomst till data en rad i taget, vilket ger dig direkt rad-för-rad kontroll över resultatuppsättningen.

Microsoft Definition

Enligt Microsofts dokumentation ger Microsoft SQL Server-satser en komplett resultatuppsättning, men det finns tillfällen då det är bäst att bearbeta det en rad i taget – vilket kan göras genom att öppna en markör på resultatuppsättningen.

Femstegsprocessen för att använda en markör

Processen att använda en SQL-markör kan generellt beskrivas enligt följande:

  1. Deklarera markör
  2. Öppna markören
  3. Hämta rader
  4. Stäng markör
  5. Avallokera markör

Viktig anmärkning

Vänligen kom ihåg att, enligt Vaidehi Pandere, är markörer pekare som upptar ditt systemminne – som annars skulle vara reserverade för andra viktiga processer. Det är därför det vanligtvis inte är den bästa idén att gå igenom en stor resultatuppsättning med hjälp av markörer – såvida det inte finns en legitim anledning till att göra det.

För mer detaljerad information om detta, se gärna min artikel Hur man använder SQL-markörer för speciella ändamål.

Exempel på SQL-markör

Först ska vi titta på ett exempel på hur en SQL-markör kan användas för att byta namn på databasobjekt ett efter ett.

För att skapa en SQL-markör vi behöver, låt oss ställa in en exempeldatabas så att vi kan köra våra skript mot den.

Setup Sample Database (UniversityV3)

Kör följande skript för att skapa och fylla i exempeldatabasen UniversityV3 med två 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

Skapa en SQL-markör för att byta namn på tabeller (_Backup)

Överväg nu att uppfylla följande specifikation genom att använda en markör:

  1. Vi måste lägga till "_Backup" till namnen på alla befintliga tabeller i en databas
  2. Tabeller som redan har "_Backup" i sitt namn ska inte bytas om

Låt oss skapa en SQL-markör för att byta namn på alla tabeller i exempeldatabasen genom att lägga till "_Backup" till varje tabells namn samtidigt som vi ser till att tabeller som innehåller "_Backup" i deras namn inte kommer att döpas om igen genom att köra följande kod:

-- 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 byta namn på skriptet och visa resultat

Tryck nu på F5 i SSMS (SQL Server Management Studio) för att köra skriptet och se resultatet:

Att uppdatera tabellernas namn i SSMS-objektutforskaren visar tydligt att vi framgångsrikt har ändrat dem enligt specifikation.

Låt oss köra skriptet igen genom att trycka på F5 igen och titta på resultaten:

Skapa en SQL-markör för att återställa _Backup Naming

Vi måste också skapa ett skript som använder en SQL-markör för att återställa namnen på de tabeller som vi just har ändrat tillbaka till de ursprungliga – vi gör detta genom att ta bort '_Backup' från deras namn.

Skriptet nedan låter oss göra just 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 återställningsskriptet och visa resultat

Att köra skriptet visar att tabellnamnen har återställts:

Dessa var exemplen på några scenarier där det är svårt att undvika att använda SQL-markörer på grund av kravets karaktär. Det är dock fortfarande möjligt att hitta ett alternativt tillvägagångssätt.

SQL-marköralternativ

Det finns två vanligaste alternativ för SQL-markörer, så låt oss titta på var och en av dem i detalj.

Alternativ 1:Tabellvariabler

Ett av dessa alternativ är tabellvariabler.

Tabellvariabler, precis som tabeller, kan lagra flera resultat – men med en viss begränsning. Enligt Microsofts dokumentation är en tabellvariabel en speciell datatyp som används för att lagra en resultatuppsättning för bearbetning vid ett senare tillfälle.

Tänk dock på att tabellvariabler bäst används med små datamängder.

Tabellvariabler kan vara mycket effektiva för småskaliga frågor eftersom de fungerar som lokala variabler och rensas automatiskt när de hamnar utanför räckvidden.

Tabellvariabelstrategi:

Vi kommer att använda tabellvariabler istället för SQL-markörer för att byta namn på alla tabeller från en databas genom att följa dessa steg:

  1. Deklarera en tabellvariabel
  2. Lagra tabellnamn och ID i den tabellvariabel vi deklarerade
  3. Sätt räknaren på 1 och få det totala antalet poster från tabellvariabeln
  4. Använd en "while"-loop så länge räknaren är mindre än eller lika med det totala antalet poster
  5. I 'while'-loopen byter vi namn på tabeller en efter en så länge de inte redan har bytt namn och ökar räknaren för varje tabell

Tabellvariabelkod:

Kör följande SQL-skript som skapar och använder en tabellvariabel för att byta namn på 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 skriptet och visa resultat

Låt oss nu köra skriptet och kontrollera resultaten:

Alternativ 2:Tillfälliga tabeller

Vi kan också använda temporära tabeller istället för SQL-markörer för att iterera resultatuppsättningen en rad i taget.

Tillfälliga tabeller har använts under lång tid och är ett utmärkt sätt att ersätta markörer för stora datamängder.

Precis som tabellvariabler kan temporära tabeller innehålla resultatuppsättningen så att vi kan utföra nödvändiga operationer genom att bearbeta den med en itererande algoritm som en "while"-loop.

Tillfällig tabellstrategi:

Vi kommer att använda en temporär tabell för att byta namn på alla tabeller i exempeldatabasen genom att följa dessa steg:

  1. Deklarera en tillfällig tabell
  2. Lagra tabellnamn och ID i den temporära tabellen som vi just deklarerade
  3. Sätt räknaren på 1 och få det totala antalet poster från den tillfälliga tabellen
  4. Använd en "while"-loop så länge räknaren är mindre än eller lika med det totala antalet poster
  5. Inom "while"-loopen, byt namn på tabeller en efter en så länge de inte redan har bytt namn och öka räknaren för varje tabell

Återställ tabellerna

Vi måste återställa tabellernas namn till deras ursprungliga form genom att ta bort '_Backup' från slutet av deras namn, så vänligen kör återställningsskriptet som vi redan har skrivit och använt ovan så att vi kan använda en annan metod för att byta namn på tabeller.

Tillfällig tabellkod:

Kör följande SQL-skript för att skapa och använda en temporär tabell för att byta namn på alla tabeller i vår databas:

-- 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 skriptet och kontrollera resultatet

Låt oss nu köra skriptet för att se resultaten:

Saker att göra

Nu när du är bekant med alternativ till SQL-markörer – som att använda tabellvariabler och temporära tabeller – försök att göra följande för att bli bekväm med att tillämpa denna kunskap i praktiken:

  1. Skapa och byt namn på index för alla tabeller i en exempeldatabas – först via en markör och sedan genom att använda alternativa metoder (tabellvariabler och temporära tabeller)
  2. Återställ namnen på tabellerna från den här artikeln till deras ursprungliga namn med alternativa metoder (temporära tabeller och tabellvariabler)
  3. Du kan också hänvisa till första exemplet i min artikel Hur man använder SQL-markörer för speciella ändamål och prova att fylla i tabeller med många rader och mäta statistiken och tiden för frågorna för att jämföra den grundläggande markörmetoden med alternativen

  1. Hur man skapar en databas från en mall i Access 2016

  2. Förhindra intilliggande/överlappande poster med EXCLUDE i PostgreSQL

  3. JDBC-teckenkodning

  4. Vad är det mest effektiva sättet att kontrollera om en post finns i Oracle?