Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Gilt für:SQL Server
Azure SQL-Datenbank
Verwaltete Azure SQL-Instanz
SQL-Datenbank in Microsoft Fabric
Wenn Sie den T-SQL-Code in Ihrem Datenbankprojekt analysieren, wird möglicherweise mindestens eine Warnung als Entwurfsprobleme kategorisiert. Sie sollten Designprobleme beheben, um die folgenden Situationen zu vermeiden:
- Nachfolgende Änderungen an Ihrer Datenbank können Anwendungen unterbrechen, die davon abhängig sind.
- Der Code erzeugt möglicherweise nicht das erwartete Ergebnis.
- Der Code könnte nicht mehr funktionieren, wenn Sie ihn mit zukünftigen Versionen von SQL Server ausführen.
Im Allgemeinen sollten Sie ein Entwurfsproblem nicht unterdrücken, da es Ihre Anwendung entweder jetzt oder in Zukunft unterbrechen könnte.
Die bereitgestellten Regeln identifizieren die folgenden Entwurfsprobleme:
- SR0001: Vermeiden Sie AUSWÄHLEN * in gespeicherten Prozeduren, Ansichten und Tabellenwertfunktionen
- SR0008: Erwägen Sie die Verwendung von SCOPE_IDENTITY anstelle von @@IDENTITY
- SR0009: Vermeiden Sie die Verwendung von Typen variabler Länge mit der Größe 1 oder 2
- SR0010: Vermeiden Sie die Verwendung veralteter Syntax, wenn Sie Tabellen oder Ansichten verknüpfen
- SR0013: Ausgabeparameter (Parameter) ist nicht in allen Codepfaden aufgefüllt
- SR0014: Datenverlust kann beim Übertragen von {Type1} in {Type2} auftreten
SR0001: Vermeiden Sie SELECT * in gespeicherten Prozeduren, Ansichten und Tabellenwertfunktionen
Wenn Sie ein Platzhalterzeichen in einer gespeicherten Prozedur, Ansicht oder Tabellenwertfunktion verwenden, um alle Spalten in einer Tabelle oder Ansicht auszuwählen, kann sich die Anzahl oder Form der zurückgegebenen Spalten ändern, wenn sich die zugrunde liegende Tabelle oder Ansicht ändert. Die Form einer Spalte ist eine Kombination aus Typ und Größe. Diese Abweichung kann in Anwendungen, die die gespeicherte Prozedur, Ansicht oder Tabellenwertfunktion verwenden, Probleme verursachen, da diese Verbraucher eine andere Anzahl von Spalten erwarten.
Beheben von Verstößen
Sie können Verbraucher der gespeicherten Prozedur, Ansicht oder Tabellenwertfunktion vor Schemaänderungen schützen, indem Sie das Wildcard-Zeichen durch eine vollqualifizierte Liste von Spaltennamen ersetzen.
Example
Im folgenden Beispiel wird zuerst eine Tabelle mit dem Namen [Table2] definiert und dann werden zwei gespeicherte Prozeduren definiert. Das erste Verfahren enthält ein SELECT *, das gegen die Regel SR0001 verstößt. Die zweite Prozedur vermeidet SELECT * und listet die Spalten in der SELECT-Anweisung explizit auf.
CREATE TABLE [dbo].[Table2]
(
[ID] INT NOT NULL IDENTITY(0, 1),
[c1] INT NOT NULL,
[Comment] NVARCHAR (50)
)
ON [PRIMARY]
CREATE PROCEDURE [dbo].[procWithWarning]
AS
BEGIN
-- Contains code that breaks rule SR0001
SELECT *
FROM [dbo].[Table2]
END
CREATE PROCEDURE [dbo].[procFixed]
AS
BEGIN
-- Explicitly lists the column names in a SELECT statement
SELECT [dbo].[Table2].[ID], [dbo].[Table2].[c1], [dbo].[Table2].[Comment]
FROM [dbo].[Table2]
END
SR0008: Erwägen Sie die Verwendung von SCOPE_IDENTITY anstelle von @@IDENTITY
Da @@IDENTITY ein globaler Identitätswert ist, wurde er möglicherweise außerhalb des aktuellen Bereichs aktualisiert und hat einen unerwarteten Wert erhalten. Trigger, einschließlich geschachtelter Trigger, die von der Replikation verwendet werden, können @@IDENTITY außerhalb Ihres aktuellen Bereichs aktualisieren.
Beheben von Verstößen
Um dieses Problem zu beheben, müssen Sie Verweise auf @@IDENTITY durch SCOPE_IDENTITY ersetzen, wodurch der neueste Identitätswert im Bereich der Benutzerausweisung zurückgegeben wird.
Example
Im ersten Beispiel wird @@IDENTITY in einer gespeicherten Prozedur verwendet, die Daten in eine Tabelle einfügt. Die Tabelle wird dann für die Zusammenführungsreplikation veröffentlicht, wodurch Trigger zu den veröffentlichten Tabellen hinzugefügt werden. Aus diesem Grund kann @@IDENTITY den Wert aus dem Einfügevorgang in eine Replikationssystemtabelle zurückgeben statt aus dem Einfügevorgang in eine Benutzertabelle.
Die Sales.Customer-Tabelle besitzt den maximalen Identitätswert 29483. Wenn Sie eine Zeile in die Tabelle einfügen, werden von @@IDENTITY und SCOPE_IDENTITY() jeweils unterschiedliche Werte zurückgegeben. SCOPE_IDENTITY() gibt den Wert aus der Einfügeoperation in die Benutzertabelle zurück, @@IDENTITY hingegen gibt den Wert aus der Einfügeoperation in die Replikationssystemtabelle zurück.
Das zweite Beispiel zeigt, wie Sie SCOPE_IDENTITY() verwenden können, um auf den eingefügten Identitätswert zuzugreifen und die Warnung zu beheben.
CREATE PROCEDURE [dbo].[ProcedureWithWarning]
@param1 INT,
@param2 NCHAR(1),
@Param3 INT OUTPUT
AS
BEGIN
INSERT INTO Sales.Customer ([TerritoryID],[CustomerType]) VALUES (@param1,@param2);
SELECT @Param3 = @@IDENTITY
END
CREATE PROCEDURE [dbo].[ProcedureFixed]
@param1 INT,
@param2 NCHAR(1),
@param3 INT OUTPUT
AS
BEGIN
INSERT INTO Sales.Customer ([TerritoryID],[CustomerType]) VALUES (@param1,@param2);
SELECT @Param3 = SCOPE_IDENTITY()
END
SR0009: Vermeiden Sie die Verwendung von Typen variabler Länge mit der Größe 1 oder 2
Wenn Sie Datentypen variabler Länge wie VARCHAR, NVARCHAR und VARBINARY verwenden, entstehen zusätzliche Speicherkosten, um die Länge des im Datentyp gespeicherten Werts nachzuverfolgen. Darüber hinaus werden Spalten mit variabler Länge nach allen Spalten mit fester Länge gespeichert, die Auswirkungen auf die Leistung haben können. Sie erhalten auch eine Warnung, wenn Sie einen Variablenlängentyp deklarieren, z. B. VARCHAR, aber keine Länge angeben. Diese Warnung tritt auf, da, falls nicht angegeben, die Standardlänge 1 ist.
Beheben von Verstößen
Wenn die Länge des Typs sehr klein (Größe 1 oder 2) und konsistent ist, deklarieren Sie sie als Typ fester Länge, z. B. CHAR, NCHAR und BINARY.
Example
Dieses Beispiel zeigt Definitionen für zwei Tabellen. In der ersten Tabelle wird eine Zeichenfolge variabler Länge mit einer Länge von 2 deklariert. Die zweite Tabelle deklariert stattdessen eine Zeichenfolge mit fester Länge, wodurch die Warnung vermieden wird.
CREATE TABLE [dbo].[TableWithWarning]
(
[ID] INT NOT NULL IDENTITY(0, 1),
[c1] INT NOT NULL PRIMARY KEY,
[c2] INT,
[c3] INT,
[SmallString] VARCHAR(2)
)
ON [PRIMARY]
CREATE TABLE [dbo].[FixedTable]
(
[ID] INT NOT NULL IDENTITY(0, 1),
[c1] INT NOT NULL PRIMARY KEY,
[c2] INT,
[c3] INT,
[SmallString] CHAR(2)
)
ON [PRIMARY]
Daten für Typen variabler Länge werden physisch nach Daten für Typen fester Länge gespeichert. Daher verursachen Sie eine Datenverschiebung, wenn Sie eine Spalte von variabler in feste Länge in einer Tabelle ändern, die nicht leer ist.
SR0010: Vermeiden Sie die Verwendung veralteter Syntax, wenn Sie Tabellen oder Ansichten verknüpfen
Verknüpfungen, die die veraltete Syntax verwenden, werden in zwei Kategorien unterteilt:
- Innerer Join: Bei einem inneren Join werden die Werte in den Spalten, die verknüpft werden, mithilfe eines Vergleichsoperators wie =, <, >= usw. verglichen. Innere Joins geben nur Zeilen zurück, wenn mindestens eine Zeile aus jeder Tabelle mit der Verknüpfungsbedingung übereinstimmt.
- Äußere Verknüpfungen: Äußere Verknüpfungen geben alle Zeilen aus mindestens einer der in der FROM-Klausel festgelegten Tabellen oder Sichten zurück, sofern diese Zeilen ggf. die WHERE- oder HAVING-Suchbedingungen erfüllen. Wenn Sie = oder = verwenden, um eine äußere Verknüpfung anzugeben, verwenden Sie veraltete Syntax.
Beheben von Verstößen
Verwenden Sie die INNER JOIN-Syntax, um einen Verstoß in einem inneren Join zu beheben.
Verwenden Sie die entsprechende OUTER JOIN-Syntax, um einen Verstoß in einer äußeren Verknüpfung zu beheben. Sie haben die folgenden Optionen:
- LEFT OUTER JOIN oder LEFT JOIN
- RIGHT OUTER JOIN oder RIGHT JOIN
Beispiele für die veraltete Syntax und die aktualisierte Syntax finden Sie in den folgenden Beispielen. Weitere Informationen zu diesen Joins finden Sie unter Joins.
Examples
Die sechs Beispiele zeigen die folgenden Optionen:
- In Beispiel 1 wird die veraltete Syntax für einen inneren Join veranschaulicht.
- In Beispiel 2 wird veranschaulicht, wie Sie Beispiel 1 aktualisieren können, um die aktuelle Syntax zu verwenden.
- In Beispiel 3 wird die veraltete Syntax für eine linke äußere Verknüpfung veranschaulicht.
- In Beispiel 4 wird veranschaulicht, wie Sie Beispiel 2 aktualisieren können, um die aktuelle Syntax zu verwenden.
- In Beispiel 5 wird die veraltete Syntax für eine rechte äußere Verknüpfung veranschaulicht.
- In Beispiel 6 wird veranschaulicht, wie Sie Beispiel 5 aktualisieren können, um die aktuelle Syntax zu verwenden.
-- Example 1: Deprecated syntax for an inner join
SELECT [T2].[c3], [T1].[c3]
FROM [dbo].[Table2] T2, [dbo].[Table1] T1
WHERE [T1].[ID] = [T2].[ID]
-- Example 2: Current syntax for an inner join
SELECT [T2].[c3], [T1].[c3]
FROM [dbo].[Table2] AS T2
INNER JOIN [dbo].[Table1] as T1
ON [T2].[ID] = [T2].[ID]
-- Example 3: Deprecated syntax for a left outer join
SELECT [T2].[c3], [T1].[c3]
FROM [dbo].[Table2] T2, [dbo].[Table1] T1
WHERE [T1].[ID] *= [T2].[ID]
-- Example 4: Fixed syntax for a left outer join
SELECT [T2].[c3], [T1].[c3]
FROM [dbo].[Table2] AS T2
LEFT OUTER JOIN [dbo].[Table1] as T1
ON [T2].[ID] = [T2].[ID]
-- Example 5: Deprecated syntax for a right outer join
SELECT [T2].[c3], [T1].[c3]
FROM [dbo].[Table2] T2, [dbo].[Table1] T1
WHERE [T1].[ID] =* [T2].[ID]
-- Example 6: Fixed syntax for a right outer join
SELECT [T2].[c3], [T1].[c3]
FROM [dbo].[Table2] AS T2
RIGHT OUTER JOIN [dbo].[Table1] as T1
ON [T2].[ID] = [T2].[ID]
SR0013: Ausgabeparameter (Parameter) ist nicht in allen Codepfaden aufgefüllt
Diese Regel identifiziert Code, in dem der Ausgabeparameter nicht auf einen Wert in einem oder mehreren Codepfaden über die gespeicherte Prozedur oder Funktion festgelegt ist. Diese Regel gibt nicht an, in welchen Pfaden der Ausgabeparameter festgelegt werden soll. Wenn mehrere Ausgabeparameter dieses Problem aufweisen, wird für jeden Parameter eine Warnung angezeigt.
Beheben von Verstößen
Sie können dieses Problem auf zwei Arten beheben. Sie können dieses Problem am einfachsten beheben, wenn Sie die Ausgabeparameter am Anfang des Prozedurtexts in einen Standardwert initialisieren. Alternativ können Sie den Ausgabeparameter auch auf einen Wert in den spezifischen Codepfaden festlegen, in denen der Parameter nicht festgelegt ist. Sie könnten jedoch einen ungewöhnlichen Codepfad in einer komplexen Vorgehensweise übersehen.
Important
Die Angabe eines Wertes in der Prozedurendeklaration, wie z.B. CREATE PROC MyProcedure (@param1 INT = 10 OUTPUT), wird das Problem nicht beheben. Sie müssen dem Ausgabeparameter innerhalb des Prozedurtexts einen Wert zuweisen.
Example
Das folgende Beispiel zeigt zwei einfache Prozeduren. Die erste Prozedur legt den Wert des Ausgabeparameters @Sum nicht fest. Die zweite Prozedur initialisiert den @Sum-Parameter am Anfang der Prozedur, wodurch sichergestellt wird, dass der Wert in allen Codepfaden festgelegt wird.
CREATE PROCEDURE [dbo].[procedureHasWarning]
(
@Value1 BIGINT,
@Value2 INT,
@Value3 INT,
@Sum INT OUTPUT
)
AS
BEGIN
-- No initialization of the output parameter
--
-- Additional statements here.
--
RETURN 0;
END
--
CREATE PROCEDURE [dbo].[procedureFixed]
(
@Value1 BIGINT,
@Value2 INT,
@Value3 INT,
@Sum INT OUTPUT
)
AS
BEGIN
-- Initialize the out parameter
SET @Sum = 0;
--
-- Additional statements here
--
RETURN 0;
END
SR0014: Datenverlust kann beim Übertragen von {Type1} in {Type2} auftreten
Wenn Datentypen Spalten, Variablen oder Parametern inkonsistent zugewiesen werden, werden sie implizit konvertiert, wenn der Transact-SQL-Code, der diese Objekte enthält, ausgeführt wird. Diese Art von Konvertierung reduziert nicht nur die Leistung, sondern verursacht in einigen Fällen auch subtilen Datenverlust. Beispielsweise kann ein Tabellenscan ausgeführt werden, wenn jede Spalte in einer WHERE-Klausel konvertiert werden muss. Schlimmer noch: Daten gehen möglicherweise verloren, wenn eine Unicode-Zeichenkette in eine ASCII-Zeichenkette konvertiert wird, die eine andere Codepage verwendet.
Diese Regel macht Folgendes NICHT:
- Den Typ einer berechneten Spalte überprüfen, da der Typ erst zur Laufzeit bekannt ist.
- Alles innerhalb einer CASE-Anweisung analysieren. Außerdem wird der Rückgabewert einer CASE-Anweisung nicht analysiert.
- Analysieren der Eingabeparameter oder des Rückgabewerts eines Aufrufs von ISNULL
In dieser Tabelle sind die von der Regel SR0014 abgedeckten Prüfungen zusammengefasst:
| Sprachkonstrukt | Was ist geprüft? | Example |
|---|---|---|
| Standardwert der Parameter | Parameterdatentyp |
|
| CREATE INDEX-Prädikat | Prädikat ist ein boolescher Wert |
|
| Argumente der LEFT- oder RIGHT-Funktionen | Zeichenkettenargumenttyp und -länge |
|
| Argumente der CAST- und CONVERT-Funktionen | Ausdrücke und Typen sind gültig |
|
| SET-Anweisung | Linke und rechte Seite verfügen über kompatible Typen |
|
| IF-Anweisungsdrädikat | Prädikat ist ein boolescher Wert |
|
| WHILE-Anweisungsdrädikat | Prädikat ist ein boolescher Wert |
|
| INSERT-Anweisung | Werte und Spalten sind korrekt |
|
| SELECT WHERE-Prädikat | Prädikat ist ein boolescher Wert |
|
| SELECT TOP-Ausdruck | Ausdruck ist eine ganze Zahl oder vom Gleitkommatyp |
|
| UPDATE-Anweisung | Ausdruck und Spalte verfügen über kompatible Typen |
|
| Prädikat „UPDATE“ | Prädikat ist ein boolescher Wert |
|
| UPDATE TOP-Ausdruck | Ausdruck ist eine ganze Zahl oder vom Gleitkommatyp |
|
| LÖSCHEN PRÄDIKAT | Prädikat ist ein boolescher Wert |
|
| DELETE TOP-Ausdruck | Ausdruck ist eine ganze Zahl oder vom Gleitkommatyp |
|
| DECLARE-Variablendeklaration | Anfangswert und Datentyp sind kompatibel |
|
| EXECUTE-Anweisungsargumente und Rückgabetyp | Parameter und Argumente |
|
| RETURN-Anweisung | Der RETURN-Ausdruck verfügt über einen kompatiblen Datentyp |
|
| MERGE-Anweisungsbedingungen | Die Bedingung ist ein boolescher Wert |
|
Beheben von Verstößen
Sie können diese Probleme vermeiden und beheben, indem Sie Datentypen konsistent und explizit konvertieren, wo sie benötigt werden. Weitere Informationen zum expliziten Konvertieren von Datentypen finden Sie auf dieser Seite auf der Microsoft-Website: CAST und CONVERT (Transact-SQL).
Example
Dieses Beispiel zeigt zwei gespeicherte Prozeduren, die Daten in eine Tabelle einfügen. Die erste Prozedur procWithWarning führt zu einer impliziten Konvertierung eines Datentyps. Die zweite Prozedur procFixed zeigt, wie Sie eine explizite Konvertierung hinzufügen können, um die Leistung zu maximieren und alle Daten aufzubewahren.
CREATE TABLE [dbo].[Table2]
(
[ID] INT NOT NULL IDENTITY(0, 1),
[c1] INT NOT NULL,
[c2] INT NOT NULL,
[c3] BIGINT NOT NULL,
[Comment] VARCHAR (25)
)
ON [PRIMARY]
CREATE PROCEDURE [dbo].[procWithWarning]
(
@Value1 INT,
@Value2 INT,
@Value3 BIGINT,
@Comment CHAR(30)
)
AS
BEGIN
INSERT INTO [Table2] ([c1], [c2], [c3], Comment)
VALUES (@Value1, @Value2, @Value3, @Comment)
END
CREATE PROCEDURE [dbo].[procFixed]
(
@Value1 INT,
@Value2 INT,
@Value3 BIGINT,
@Comment CHAR(10)
)
AS
BEGIN
INSERT INTO [Table2] ([c1], [c2], [c3], Comment)
VALUES (@Value1, @Value2, @Value3, CAST(@Comment AS VARCHAR(25)))
END