共用方式為


T-SQL 效能問題

適用於:Microsoft Fabric 中的 SQL ServerAzure SQL 資料庫 Azure SQL 受控執行個體 SQL 資料庫

當您在資料庫專案中分析 T-SQL 程式碼時,可能會將一或多個警告分類為效能問題。 您應該解決效能問題,以避免下列情況:

  • 執行程式碼時,就會發生資料表掃描。

一般而言,如果資料表包含的資料很少,掃描不會造成效能大幅下降,您有可能隱藏效能問題。

提供的規則可識別下列效能問題:

SR0004:避免在 IN 述詞中使用沒有索引的資料行作為測試運算式

如果您使用 WHERE 子句來參考一或多個未做為 IN 述詞一部分編製索引的資料行,則會導致資料表掃描。 資料表掃描可降低效能。

如何修正違規

若要修正這個問題,必須進行下列其中一項變更:

  • 變更 IN 述詞,只參考具有索引的資料行。
  • 將索引新增至 IN 述詞參考且尚未具有索引的任何資料行。

範例

在此範例中,簡單的 SELECT 陳述式會參考沒有索引的資料行 [c1]。 第二個陳述式定義了索引,您可以新增該索引以解析此警告。

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:避免在 LIKE 述詞中使用開頭為 "%" 的模式

如果您使用包含 LIKE 述詞的 WHERE 子句,例如 '%pattern string' 來搜尋資料行中任何地方可能發生的文字,則可能會造成資料表掃描。

如何修正違規

若要解決此問題,您應該變更搜尋字串,使其以非萬用字元 (%) 的字元開頭,或者您應該建立全文檢索索引。

範例

在第一個範例中,SELECT 陳述式會造成資料表掃描,因為搜尋字串以萬用字元開頭。 在第二個範例中,陳述式會造成索引搜尋,因為搜尋字元串不是以萬用字元開頭。 索引搜尋只會擷取符合 WHERE 子句的資料列。

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:將資料行參考移至比較運算子的一端,以使用資料行索引

如果您的程式碼比較包含資料行參考的運算式,可能會導致資料表掃描。

如何修正違規

若要解決此問題,您必須重新處理比較,讓資料行參考單獨出現在比較運算子的一端,而不是在運算式內。 當您單獨在比較運算子的一端執行具有資料行參考的程式碼時,SQL Server 可以使用資料行索引,而且不會執行任何資料表掃描。

範例

在第一個程式中,WHERE 子句在運算式中包含資料行 [c1],作為比較的一部分。 在第二個程式中,比較結果完全相同,但絕對不需要資料表掃描。

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:在運算式中的可為 Nulll 資料行上使用 ISNULL(column, default_value)

如果您的程式碼將兩 NULL 個值或一個 NULL 值與任何其他值進行比較,則程式碼會傳回未知的結果。

如何修正違規

您應該明確地指出如何處理 NULL 比較運算式中的值,方法是包裝可包含 NULL 函式中 ISNULL 值的每個資料行。

範例

此範例顯示簡單的資料表定義和兩個預存程序。 資料表包含資料行 c2,該資料行可以包含 NULL 值。 第一個程序 ProcedureWithWarning 會將 c2 與常數值進行比較。 第二個程序會透過呼叫 ISNULL 函式來包裝 c2,以修正問題。

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:從 WHERE 述詞擷取決定性函式呼叫

在 WHERE 述詞中,如果函式呼叫的值不相依於選取的資料,則函式呼叫會具確定性。 這類呼叫可能會導致不必要的資料表掃描,因而降低資料庫效能。

如何修正違規

若要解決此問題,您可以將呼叫的結果指派給在 WHERE 述詞中使用的變數。

範例

在第一個範例中,預存程序會在 WHERE 述詞中包含確定性函式呼叫 ABS(@param1)。 在第二個範例中,暫存變數會保存呼叫的結果。

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