Condividi tramite


Problemi di prestazioni di T-SQL

Si applica a:SQL ServerDatabase SQL di AzureIstanza gestita di SQL di AzureDatabase SQL in Microsoft Fabric

Quando si analizza il codice T-SQL nel progetto di database, uno o più avvisi potrebbero essere classificati come problemi di prestazioni. È consigliabile risolvere un problema di prestazioni per evitare la situazione seguente:

  • Un'analisi di tabella viene eseguita quando viene eseguito il codice.

In generale, è possibile eliminare un problema di prestazioni se la tabella contiene dati così piccoli che un'analisi non causerà un calo significativo delle prestazioni.

Le regole fornite identificano i problemi di prestazioni seguenti:

SR0004: evitare di usare colonne che non dispongono di indici come espressioni di test nei predicati IN

Se usi una clausola WHERE che fa riferimento a una o più colonne non indicizzate come parte di un predicato IN, viene eseguita una scansione della tabella. La scansione della tabella riduce le prestazioni.

Come correggere le violazioni

Per risolvere questo problema, è necessario apportare una delle modifiche seguenti:

  • Modificare il predicato IN in modo che faccia riferimento solo alle colonne con un indice.
  • Aggiungere un indice a qualsiasi colonna a cui fa riferimento il predicato IN e che non dispone già di un indice.

Example

In questo esempio, una semplice istruzione SELECT fa riferimento a una colonna [c1], che non ha un indice. La seconda istruzione definisce un indice che è possibile aggiungere per risolvere questo avviso.

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: evitare di usare modelli che iniziano con "%" nei predicati LIKE

È possibile eseguire un'analisi di tabella se si usa una clausola WHERE contenente un predicato LIKE, ad esempio '%pattern stringa' per cercare testo che può verificarsi in qualsiasi punto di una colonna.

Come correggere le violazioni

Per risolvere questo problema, devi modificare la stringa di ricerca in modo che inizi con un carattere che non sia un carattere jolly (%), oppure creare un indice di testo completo.

Example

Nel primo esempio l'istruzione SELECT genera una scansione della tabella perché la stringa di ricerca inizia con un carattere jolly. Nel secondo esempio, l'istruzione genera una ricerca tramite indice perché la stringa di ricerca non inizia con un carattere jolly. Una ricerca di indice recupera solo le righe che corrispondono alla clausola 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: spostare un riferimento di colonna a un lato di un operatore di confronto per usare un indice di colonna

Il codice potrebbe causare un'analisi di tabella se confronta un'espressione che contiene un riferimento a una colonna.

Come correggere le violazioni

Per risolvere questo problema, è necessario rielaborare il confronto in modo che il riferimento alla colonna venga visualizzato da solo su un lato dell'operatore di confronto, anziché all'interno di un'espressione. Quando si esegue il codice con il riferimento di colonna da solo su un lato dell'operatore di confronto, SQL Server può usare l'indice di colonna e non viene eseguita alcuna analisi di tabella.

Example

Nella prima procedura, una clausola WHERE include la colonna [c1] in un'espressione come parte di un confronto. Nella seconda procedura i risultati del confronto sono identici ma non richiedono mai un'analisi di tabella.

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: Usare ISNULL(column, default_value) per colonne nullable nelle espressioni

Se il codice confronta due NULL valori o un NULL valore con qualsiasi altro valore, il codice restituisce un risultato sconosciuto.

Come correggere le violazioni

È consigliabile indicare in modo esplicito come gestire NULL i valori nelle espressioni di confronto eseguendo il wrapping di ogni colonna che può contenere un NULL valore in una ISNULL funzione.

Example

In questo esempio viene illustrata una definizione di tabella semplice e due stored procedure. La tabella contiene una colonna, c2, che può contenere un NULL valore. La prima procedura, ProcedureWithWarning, confronta c2 a un valore costante. La seconda procedura risolve il problema incapsulando c2 con una chiamata alla funzione ISNULL.

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: Estrarre chiamate di funzione deterministiche dai predicati WHERE

In un predicato WHERE, una chiamata di funzione è deterministica se il relativo valore non dipende dai dati selezionati. Tali chiamate potrebbero causare analisi di tabelle non necessarie, riducendo le prestazioni del database.

Come correggere le violazioni

Per risolvere questo problema, è possibile assegnare il risultato della chiamata a una variabile usata nel predicato WHERE.

Example

Nel primo esempio la stored procedure include una chiamata di funzione deterministica, ABS(@param1), nel predicato WHERE. Nel secondo esempio una variabile temporanea contiene il risultato della chiamata.

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