T-SQL 성능 문제
적용 대상: Microsoft Fabric의 SQL ServerAzure SQL Database Azure SQL Managed Instance SQL 데이터베이스
데이터베이스 프로젝트에서 T-SQL 코드를 분석할 때 하나 이상의 경고가 성능 문제로 분류될 수 있습니다. 다음 상황을 방지하려면 성능 문제를 해결해야 합니다.
- 테이블 검색은 코드가 실행될 때 발생합니다.
일반적으로 테이블에 데이터가 너무 적어서 검색으로 인해 성능이 크게 떨어지지 않는 경우 성능 문제가 표시되지 않을 수 있습니다.
제공된 규칙은 다음과 같은 성능 문제를 식별합니다.
- SR0004: 인덱스가 없는 열을 IN 조건자의 테스트 식으로 사용하지 마세요.
- SR0005: LIKE 조건자에서 "%"로 시작하는 패턴을 사용하지 않습니다.
- SR0006: 열 인덱스 사용을 위해 비교 연산자의 한 쪽으로 열 참조 이동
- SR0007: 식의 null 허용 열에서 ISNULL(열, default_value)을 사용하세요.
- SR0015: WHERE 조건자에서 결정 함수 호출 추출
SR0004: 인덱스가 없는 열을 IN 조건자의 테스트 식으로 사용하지 마세요.
IN 조건자의 일부로 인덱싱되지 않은 하나 이상의 열을 참조하는 WHERE 절을 사용하는 경우 테이블 검색이 발생합니다. 테이블 검색은 성능을 저하시킵니다.
위반 문제를 해결하는 방법
이 문제를 해결하려면 다음 중 하나를 변경해야 합니다.
- 인덱스가 있는 열만 참조하도록 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 조건자에서 "%"로 시작하는 패턴을 사용하지 않습니다.
'%pattern string'과 같은 LIKE 조건자가 포함된 WHERE 절을 사용하여 열의 아무 곳에서나 발생할 수 있는 텍스트를 검색하는 경우 테이블 검색이 발생할 수 있습니다.
위반 문제를 해결하는 방법
이 문제를 해결하려면 와일드카드(%)가 아닌 문자로 시작하도록 검색 문자열을 변경하거나 전체 텍스트 인덱스를 만들어야 합니다.
예시
첫 번째 예제에서 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: 식의 null 허용 열에서 ISNULL(열, default_value)을 사용하세요.
코드에서 두 NULL
값 또는 NULL
값을 다른 값과 비교하는 경우 코드는 알 수 없는 결과를 반환합니다.
위반 문제를 해결하는 방법
NULL
함수에 NULL
값을 포함 할 수 있는 각 열을 래핑하여 비교 식의 ISNULL
값을 처리하는 방법을 명시적으로 나타내야 합니다.
예시
이 예제에서는 간단한 테이블 정의와 두 개의 저장 프로시저를 보여 줍니다. 테이블에는 NULL
값을 포함할 수 있는 열 c2
이(가) 포함되어 있습니다. 첫 번째 프로시저 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 조건자에서 사용하는 변수에 호출 결과를 할당할 수 있습니다.
예시
첫 번째 예제에서 저장 프로시저는 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