Freigeben über


T-SQL-Leistungsprobleme

Gilt für: SQL Server Azure SQL-Datenbank Azure SQL Managed Instance

Wenn Sie den T-SQL-Code in Ihrem Datenbankprojekt analysieren, wird möglicherweise mindestens eine Warnung als Leistungsprobleme kategorisiert. Sie sollten Leistungsprobleme beheben, um die folgende Situation zu vermeiden:

  • Beim Ausführen des Codes erfolgt ein Tabellenscan.

Im Allgemeinen können Sie ein Leistungsproblem unterdrücken, wenn die Tabelle so wenig Daten enthält, dass ein Scan die Leistung nicht erheblich reduziert.

Die bereitgestellten Regeln identifizieren die folgenden Leistungsprobleme:

SR0004: Vermeiden Sie die Verwendung von Spalten, die keine Indizes als Testausdrücke in IN-Prädikaten aufweisen

Sie verursachen einen Tabellenscan, wenn Sie eine WHERE-Klausel verwenden, die auf eine oder mehrere Spalten verweist, die nicht als Teil eines IN-Prädikats indiziert sind. Der Tabellenscan reduziert die Leistung.

Behandeln von Verstößen

Sie müssen zum Lösen dieses Problems eine der folgenden Änderungen vornehmen:

  • Ändern Sie das IN-Prädikat so, dass nur auf die Spalten verwiesen wird, die einen Index aufweisen.
  • Fügen Sie einen Index zu jeder Spalte hinzu, auf die das IN-Prädikat verweist und die noch keinen Index hat.

Beispiel

In diesem Beispiel verweist eine einfache SELECT-Anweisung auf eine Spalte, [c1], die keinen Index hat. Die zweite Anweisung definiert einen Index, den Sie hinzufügen können, um diese Warnung zu beheben.

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: Vermeiden Sie die Verwendung von Mustern, die mit „%“ in LIKE-Prädikaten beginnen

Sie können einen Tabellenscan verursachen, wenn Sie eine WHERE-Klausel verwenden, die ein LIKE-Prädikat wie „%pattern string“ enthält, um nach Text zu suchen, der an einer beliebigen Stelle in einer Spalte auftreten kann.

Behandeln von Verstößen

Um dieses Problem zu beheben, sollten Sie die Suchzeichenfolge so ändern, dass sie mit einem Zeichen beginnt, das kein Wildcard (%) ist, oder Sie sollten einen Volltextindex erstellen.

Beispiel

Im ersten Beispiel bewirkt die SELECT-Anweisung einen Tabellenscan, da die Suchzeichenfolge mit einem Wildcard-Zeichen beginnt. Im zweiten Beispiel bewirkt die Anweisung eine Indexsuche, da die Suchzeichenfolge nicht mit einem Platzhalterzeichen beginnt. Eine Indexsuche ruft nur die Zeilen ab, die der WHERE-Klausel entsprechen.

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: Verschieben eines Spaltenverweises auf eine Seite eines Vergleichsoperators zur Verwendung eines Spaltenindex

Ihr Code könnte einen Tabellenscan verursachen, wenn ein Ausdruck verglichen wird, der einen Spaltenverweis enthält.

Behandeln von Verstößen

Um dieses Problem zu beheben, müssen Sie den Vergleich umarbeiten, damit der Spaltenverweis allein auf einer Seite des Vergleichsoperators statt innerhalb eines Ausdrucks angezeigt wird. Wenn Sie den Code ausführen, der den Spaltenverweis allein auf einer Seite des Vergleichsoperators enthält, kann SQL Server den Spaltenindex verwenden, und es wird kein Tabellenscan ausgeführt.

Beispiel

In der ersten Prozedur enthält eine WHERE-Klausel die Spalte [c1] in einem Ausdruck als Teil eines Vergleichs. Im zweiten Verfahren sind die Vergleichsergebnisse identisch, erfordern aber nie einen Tabellenscan.

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: Verwenden von ISNULL (Spalte, default_value) für nullfähige Spalten in Ausdrücken

Wenn Ihr Code zwei NULL-Werte oder einen NULL-Wert mit einem anderen Wert vergleicht, gibt ihr Code ein unbekanntes Ergebnis zurück.

Behandeln von Verstößen

Sie sollten ausdrücklich angeben, wie NULL-Werte in Vergleichsausdrücken behandelt werden sollen, indem Sie jede Spalte, die einen NULL-Wert enthalten kann, in eine ISNULL-Funktion einschließen.

Beispiel

Dieses Beispiel zeigt eine einfache Tabellendefinition und zwei gespeicherte Prozeduren. Die Tabelle enthält eine Spalte, c2, die einen NULL-Wert enthalten kann. Die erste Prozedur, ProcedureWithWarning, vergleicht c2 mit einem Konstantenwert. Die zweite Prozedur behebt das Problem durch Umbruch von c2 mit einem Aufruf der ISNULL-Funktion.

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: Extrahieren deterministischer Funktionsaufrufe aus WHERE-Prädikaten

In einem WHERE-Prädikat ist ein Funktionsaufruf deterministisch, wenn sein Wert nicht von den ausgewählten Daten abhängt. Solche Aufrufe könnten unnötige Tabellenscans verursachen, wodurch die Datenbankleistung verringert wird.

Behandeln von Verstößen

Um dieses Problem zu beheben, können Sie das Ergebnis des Aufrufs einer Variablen zuweisen, die Sie im WHERE-Prädikat verwenden.

Beispiel

Im ersten Beispiel enthält die gespeicherte Prozedur einen deterministischen Funktionsaufruf,ABS(@param1), im WHERE-Prädikat. Im zweiten Beispiel enthält eine temporäre Variable das Ergebnis des Aufrufs.

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