Problemas de desempenho do T-SQL
Aplica-se a: SQL Server Banco de Dados SQL do Azure Instância Gerenciada de SQL do Azure Banco de dados SQL no Microsoft Fabric
Quando você analisa o código T-SQL em seu projeto de banco de dados, um ou mais avisos podem ser categorizados como problemas de desempenho. Você deve resolver um problema de desempenho para evitar a seguinte situação:
- Uma verificação de tabela ocorre quando o código é executado.
Em geral, você pode suprimir um problema de desempenho se a tabela contiver tão poucos dados que uma verificação não fará com que o desempenho caia significativamente.
As regras fornecidas identificam os seguintes problemas de desempenho:
- SR0004: evite usar colunas que não tenham índices como expressões de teste em predicados IN
- SR0005: evite usar padrões que começam com "%" em predicados LIKE
- SR0006: mova uma referência de coluna para um lado de um operador de comparação para usar um índice de coluna
- SR0007: use ISNULL(column, default_value) em colunas anuláveis em expressões
- SR0015: extraia chamadas de função determinística de predicados WHERE
SR0004: evite usar colunas que não tenham índices como expressões de teste em predicados IN
Você causará uma verificação de tabela se usar uma cláusula WHERE que faz referência a uma ou mais colunas que não estão indexadas como parte de um predicado IN. A verificação de tabela reduz o desempenho.
Como corrigir violações
Para resolver esse problema, é necessário fazer uma das seguintes alterações:
- Altere o predicado IN para fazer referência apenas às colunas que têm um índice.
- Adicione um índice a qualquer coluna à qual o predicado IN faça referência e que ainda não tenha um índice.
Exemplo
Neste exemplo, uma instrução SELECT simples faz referência a uma coluna, [c1], que não tinha um índice. A segunda instrução define um índice que você pode adicionar para resolver esse aviso.
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: evite usar padrões que começam com "%" em predicados LIKE
Você pode causar uma verificação de tabela se usar uma cláusula WHERE que contenha um predicado LIKE, como ''%pattern string'', para pesquisar texto que pode ocorrer em qualquer lugar em uma coluna.
Como corrigir violações
Para resolver esse problema, você deve alterar a cadeia de caracteres de pesquisa para que ela comece com um caractere que não seja um curinga (%), ou você deve criar um índice de texto completo.
Exemplo
No primeiro exemplo, a instrução SELECT causa uma verificação de tabela porque a cadeia de caracteres de pesquisa começa com um caractere curinga. No segundo exemplo, a instrução causa uma busca de índice porque a cadeia de caracteres de pesquisa não começa com um caractere curinga. Uma busca de índice recupera apenas as linhas que correspondem à cláusula 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: mova uma referência de coluna para um lado de um operador de comparação para usar um índice de coluna
Seu código pode causar uma verificação de tabela se comparar uma expressão que contém uma referência de coluna.
Como corrigir violações
Para resolver esse problema, você deve retrabalhar a comparação para que a referência de coluna apareça sozinha em um lado do operador de comparação, em vez de dentro de uma expressão. Quando você executa o código que tem a referência de coluna sozinha em um lado do operador de comparação, o SQL Server pode usar o índice de coluna e nenhuma verificação de tabela é executada.
Exemplo
No primeiro procedimento, uma cláusula WHERE inclui a coluna [c1] em uma expressão como parte de uma comparação. No segundo procedimento, os resultados da comparação são idênticos, mas nunca requerem uma verificação de tabela.
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: use ISNULL(column, default_value) em colunas anuláveis em expressões
Se o código comparar dois valores NULL
ou um valor NULL
com qualquer outro valor, o código retornará um resultado desconhecido.
Como corrigir violações
Você deve indicar explicitamente como lidar com valores NULL
em expressões de comparação encapsulando cada coluna que pode conter um valor NULL
em uma função ISNULL
.
Exemplo
Este exemplo mostra uma definição de tabela simples e dois procedimentos armazenados. A tabela contém uma coluna, c2
, que pode conter um valor NULL
. O primeiro procedimento, ProcedureWithWarning
, compara c2
a um valor constante. O segundo procedimento corrige o problema encapsulando c2
com uma chamada para a função 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: extraia chamadas de função determinística de predicados WHERE
Em um predicado WHERE, uma chamada de função será determinística se seu valor não depender dos dados selecionados. Essas chamadas podem causar verificações de tabela desnecessárias, o que diminui o desempenho do banco de dados.
Como corrigir violações
Para resolver esse problema, você pode atribuir o resultado da chamada a uma variável que você usa no predicado WHERE.
Exemplo
No primeiro exemplo, o procedimento armazenado inclui uma chamada de função determinística, ABS(@param1)
, no predicado WHERE. No segundo exemplo, uma variável temporária contém o resultado da chamada.
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