Проблемы с производительностью T-SQL
Область применения: SQL Server База данных SQL Azure Управляемый экземпляр SQL Azure базе данных SQL в Microsoft Fabric
При анализе кода T-SQL в проекте базы данных один или несколько предупреждений могут быть классифицированы как проблемы с производительностью. Чтобы избежать следующей ситуации, следует устранить проблему производительности:
- Сканирование таблицы происходит при выполнении кода.
Как правило, вы можете отключить проблему производительности, если таблица содержит так мало данных, что проверка не приведет к значительному снижению производительности.
Указанные правила определяют следующие проблемы с производительностью:
- SR0004. Избегайте использования столбцов, у которых нет индексов в качестве тестовых выражений в предикатах IN
- SR0005: избегайте использования шаблонов, начинающихся с "%" в предикатах LIKE
- SR0006. Перемещение ссылки на столбец на одну сторону оператора сравнения для использования индекса столбца
- SR0007: используйте ISNULL(column, default_value) для столбцов, допускающих значение NULL, в выражениях
- SR0015: извлечение детерминированных вызовов функций из предикатов WHERE
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
Вы можете вызвать проверку таблицы, если вы используете предложение WHERE, содержащее предикат LIKE, например "%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: используйте ISNULL(column, default_value) для столбцов, допускающих значение NULL, в выражениях
Если код сравнивает два NULL
значения или NULL
значение с любым другим значением, код возвращает неизвестный результат.
Устранение нарушений
Необходимо явно указать, как обрабатывать NULL
значения в выражениях сравнения путем упаковки каждого столбца, который может содержать NULL
значение в ISNULL
функции.
Пример
В этом примере показано простое определение таблицы и две хранимые процедуры. Таблица содержит столбец, c2
который может содержать NULL
значение. Первая процедура ProcedureWithWarning
сравнивается c2
с константным значением. Вторая процедура устраняет проблему путем упаковки c2
с вызовом 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: извлечение детерминированных вызовов функций из предикатов WHERE
В предикате WHERE вызов функции детерминирован, если его значение не зависит от выбранных данных. Такие вызовы могут привести к ненужным сканированиям таблиц, что снижает производительность базы данных.
Устранение нарушений
Чтобы устранить эту проблему, можно назначить результат вызова переменной, используемой в предикате WHERE.
Пример
В первом примере хранимая процедура включает детерминированный вызов функции в ABS(@param1)
предикате WHERE. Во втором примере временная переменная содержит результат вызова.
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