Prestandaproblem med T-SQL

Gäller för:SQL ServerAzure SQL DatabaseAzure SQL Managed InstanceSQL-databas i Microsoft Fabric

När du analyserar T-SQL-koden i databasprojektet kan en eller flera varningar kategoriseras som prestandaproblem. Du bör åtgärda ett prestandaproblem för att undvika följande situation:

  • En tabellgenomsökning sker när koden körs.

I allmänhet kan du förhindra prestandaproblem om tabellen innehåller så lite data att en genomsökning inte leder till att prestandan minskar avsevärt.

De angivna reglerna identifierar följande prestandaproblem:

SR0004: Undvik att använda kolumner som inte har index som testuttryck i IN-predikater

Du orsakar en tabellgenomsökning om du använder en WHERE-sats som refererar till en eller flera kolumner som inte indexeras som en del av en IN-predikat. Tabellgenomsökningen minskar prestandan.

Så här åtgärdar du överträdelser

För att lösa det här problemet måste du göra någon av följande ändringar:

  • Ändra IN-predikatet till att endast referera till de kolumner som har ett index.
  • Lägg till ett index i en kolumn som IN predikat refererar till och som inte redan har ett index.

Example

I det här exemplet refererar en enkel SELECT-instruktion till en kolumn, [c1], som inte hade något index. Den andra instruktionen definierar ett index som du kan lägga till för att lösa den här varningen.

CREATE PROCEDURE [dbo].[Procedure3WithWarnings]
AS
SELECT [Comment]
FROM [dbo].[Table2]
WHERE [c1] IN (1, 2, 3)

CREATE INDEX [IX_Table2_C1]
ON [dbo].[Table2] (c1);

SR0005: Undvik att använda mönster som börjar med "%" i LIKE-predikat

Du kan orsaka en tabellgenomsökning om du använder en WHERE-sats som innehåller ett LIKE-predikat som "%pattern sträng" för att söka efter text som kan förekomma var som helst i en kolumn.

Så här åtgärdar du överträdelser

För att lösa det här problemet bör du ändra söksträngen så att den börjar med ett tecken som inte är ett jokertecken (%), eller så bör du skapa ett fulltextindex.

Example

I det första exemplet orsakar SELECT-instruktionen en tabellgenomsökning eftersom söksträngen börjar med ett jokertecken. I det andra exemplet föranleder instruktionen en indexsökning eftersom söksträngen inte börjar med ett jokertecken. En indexsökning hämtar endast de rader som matchar WHERE-satsen.

SELECT [dbo].[Table2].[ID], [dbo].[Table2].[c1], [dbo].[Table2].[c2], [dbo].[Table2].[c3], [dbo].[Table2].[Comment]
FROM dbo.[Table2]
WHERE Comment LIKE '%pples'

SELECT [dbo].[Table2].[ID], [dbo].[Table2].[c1], [dbo].[Table2].[c2], [dbo].[Table2].[c3], [dbo].[Table2].[Comment]
FROM dbo.[Table2]
WHERE Comment LIKE 'A%'

SR0006: Flytta en kolumnreferens till ena sidan av en jämförelseoperator för att använda ett kolumnindex

Koden kan orsaka en tabellgenomsökning om den jämför ett uttryck som innehåller en kolumnreferens.

Så här åtgärdar du överträdelser

För att lösa det här problemet måste du omarbeta jämförelsen så att kolumnreferensen visas ensam på ena sidan av jämförelseoperatorn i stället för inuti ett uttryck. När du kör koden som har kolumnreferensen ensam på ena sidan av jämförelseoperatorn kan SQL Server använda kolumnindexet och ingen tabellgenomsökning utförs.

Example

I den första proceduren innehåller en WHERE-sats kolumnen [c1] i ett uttryck som en del av en jämförelse. I den andra proceduren är jämförelseresultaten identiska men kräver aldrig en tabellgenomsökning.

CREATE PROCEDURE [dbo].[Procedure3WithWarnings]
@param1 int
AS
SELECT [c1], [c2], [c3], [Comment]
FROM [dbo].[Table2]
WHERE ([c1] + 5 > @param1)

CREATE PROCEDURE [dbo].[Procedure3Fixed]
@param1 int
AS
SELECT [c1], [c2], [c3], [Comment]
FROM [dbo].[Table2]
WHERE ([c1] > (@param1 - 5))

SR0007: Använd ISNULL(column, default_value) på nullbara kolumner i uttryck

Om koden jämför två NULL värden eller ett NULL värde med något annat värde returnerar koden ett okänt resultat.

Så här åtgärdar du överträdelser

Du bör uttryckligen ange hur du hanterar NULL värden i jämförelseuttryck genom att omsluta varje kolumn som kan innehålla ett NULL värde i en ISNULL funktion.

Example

Det här exemplet visar en enkel tabelldefinition och två lagrade procedurer. Tabellen innehåller en kolumn, c2, som kan innehålla ett NULL värde. Den första proceduren, ProcedureWithWarning, jämförs c2 med ett konstant värde. Den andra proceduren åtgärdar problemet genom att omsluta c2 med ett anrop till ISNULL funktionen.

CREATE TABLE [dbo].[Table1]
(
[ID] INT NOT NULL IDENTITY(0, 1),
[c1] INT NOT NULL PRIMARY KEY,
[c2] INT
)
ON [PRIMARY]

CREATE PROCEDURE [dbo].[ProcedureWithWarning]
AS
BEGIN
SELECT COUNT(*) FROM [dbo].[Table1]
 WHERE [c2] > 2;
END

CREATE PROCEDURE [dbo].[ProcedureFixed]
AS
BEGIN
SELECT COUNT(*) FROM [dbo].[Table1]
WHERE ISNULL([c2],0) > 2;
END

SR0015: Extrahera deterministiska funktionsanrop från WHERE-predikat

I ett WHERE-predikat är ett funktionsanrop deterministiskt om dess värde inte är beroende av valda data. Sådana anrop kan orsaka onödiga tabellgenomsökningar, vilket minskar databasens prestanda.

Så här åtgärdar du överträdelser

För att lösa det här problemet kan du tilldela resultatet av anropet till en variabel som du använder i WHERE-predikatet.

Example

I det första exemplet innehåller den lagrade proceduren ett deterministiskt funktionsanrop, ABS(@param1), i WHERE-predikatet. I det andra exemplet innehåller en tillfällig variabel resultatet av anropet.

CREATE PROCEDURE [dbo].[Procedure2WithWarning]
@param1 INT = 0,
AS
BEGIN
SELECT [c1], [c2], [c3], [SmallString]
FROM [dbo].[Table1]
WHERE [c2] > ABS(@param1)
END

CREATE PROCEDURE [dbo].[Procedure2Fixed]
@param1 INT = 0,
AS
BEGIN
DECLARE @AbsOfParam1 INT
SET @AbsOfParam1 = ABS(@param1)

SELECT [c1], [c2], [c3], [SmallString]
FROM [dbo].[Table1]
WHERE [c2] > @AbsOfParam1
END