Problemas de rendimiento de T-SQL
Se aplica a: SQL Server Azure SQL Database Azure SQL Managed Instance
Al analizar el código T-SQL en el proyecto de base de datos, una o varias advertencias podrían clasificarse como problemas de rendimiento. Debe solucionar los problemas de rendimiento para evitar la situación siguiente:
- Un recorrido de tabla se produce cuando se ejecuta el código.
En general, puede suprimir un problema de rendimiento si la tabla contiene tan pocos datos que un examen no hará que el rendimiento baje significativamente.
Las reglas proporcionadas identifican los siguientes problemas de rendimiento:
- SR0004: Evite usar columnas que no tengan índices como expresiones de prueba en predicados IN
- SR0005: Evite usar patrones que empiecen por "%" en predicados LIKE
- SR0006: Mueva una referencia de columna a un lado de un operador de comparación para usar un índice de columna
- SR0007: Use ISNULL(column, default_value) en columnas que aceptan valores NULL en expresiones
- SR0015: Extraiga llamadas de función deterministas de predicados WHERE
SR0004: Evite usar columnas que no tengan índices como expresiones de prueba en predicados IN
Se produce un recorrido de tabla si se usa una cláusula WHERE que hace referencia a una o varias columnas sin índices como parte de un predicado IN. El recorrido de tabla reduce el rendimiento.
Cómo corregir infracciones
Para corregir este problema, debe realizar uno de los cambios siguientes:
- Cambie el predicado IN para hacer referencia solo a las columnas que tienen un índice.
- Agregue un índice a cualquier columna a la que hace referencia el predicado IN y que aún no tiene un índice.
Ejemplo
En este ejemplo, una instrucción SELECT simple hace referencia a una columna, [c1], que no tenía índice. La segunda instrucción define un índice que puede agregar para resolver esta advertencia.
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 patrones que empiecen por "%" en predicados LIKE
Podría provocar un recorrido de tabla si usa una cláusula WHERE que contiene un predicado LIKE, como "%cadena de patrón" para buscar texto que pueda producirse en cualquier parte de una columna.
Cómo corregir infracciones
Para resolver este problema, debe cambiar la cadena de búsqueda para que comience con un carácter que no sea un carácter comodín (%) o debe crear un índice de texto completo.
Ejemplo
En el primer ejemplo, la instrucción SELECT provoca un recorrido de tabla porque la cadena de búsqueda comienza con un carácter comodín. En el segundo ejemplo, la instrucción provoca una búsqueda de índice porque la cadena de búsqueda no comienza con un carácter comodín. Una búsqueda de índice recupera solo las filas que coinciden con la 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: Mueva una referencia de columna a un lado de un operador de comparación para usar un índice de columna
El código podría provocar un recorrido de tabla si compara una expresión que contiene una referencia de columna.
Cómo corregir infracciones
Para resolver este problema, debe volver a realizar la comparación para que la referencia de columna aparezca sola en un lado del operador de comparación, en lugar de dentro de una expresión. Al ejecutar el código que tiene solo la referencia de columna en un lado del operador de comparación, SQL Server puede usar el índice de columna y no se realiza ningún recorrido de tabla.
Ejemplo
En el primer procedimiento, una cláusula WHERE incluye la columna [c1] en una expresión como parte de una comparación. En el segundo procedimiento, los resultados de la comparación son idénticos, pero nunca requieren un recorrido de tabla.
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) en columnas que aceptan valores NULL en expresiones
Si el código compara dos valores NULL
o un valor NULL
con cualquier otro valor, el código devuelve un resultado desconocido.
Cómo corregir infracciones
Debe indicar explícitamente cómo controlar los valores NULL
en expresiones de comparación ajustando cada columna que puede contener un valor NULL
en una función ISNULL
.
Ejemplo
En este ejemplo se muestra una definición de tabla simple y dos procedimientos almacenados. La tabla contiene una columna, c2
, que puede contener un valor NULL
. El primer procedimiento, ProcedureWithWarning
, compara c2
con un valor constante. El segundo procedimiento corrige el problema encapsulando c2
con una llamada a la función 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: Extraiga llamadas de función deterministas de predicados WHERE
En un predicado WHERE, una llamada de función es determinista si su valor no depende de los datos seleccionados. Estas llamadas podrían provocar recorridos de tabla innecesarios, lo que reduce el rendimiento de la base de datos.
Cómo corregir infracciones
Para resolver este problema, puede asignar el resultado de la llamada a una variable que use en el predicado WHERE.
Ejemplo
En el primer ejemplo, el procedimiento almacenado incluye una llamada de función determinista, ABS(@param1)
, en el predicado WHERE. En el segundo ejemplo, una variable temporal contiene el resultado de la llamada.
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