계획 지침에서 INDEX 및 FORCESEEK 쿼리 힌트 사용
INDEX 및 FORCESEEK 테이블 힌트를 쿼리 힌트로 지정할 수 있습니다. 쿼리 힌트로 지정할 경우 이러한 힌트는 인라인 테이블 또는 뷰 힌트와 동일한 방식으로 동작합니다.
INDEX 힌트는 쿼리 최적화 프로그램이 지정한 인덱스만 사용하여 쿼리의 참조된 테이블 또는 뷰에 있는 데이터에 액세스하도록 합니다. FORCESEEK 힌트는 최적화 프로그램이 Index Seek 연산만 사용하여 참조된 테이블 또는 뷰에 있는 데이터에 액세스하도록 합니다. 이러한 힌트를 계획 지침의 OPTION 절에 사용하면 쿼리 최적화에 영향을 미칠 수 있습니다. 쿼리가 계획 지침과 일치하면 컴파일 및 최적화하기 전에 계획 지침에 지정된 OPTION 절이 쿼리에 추가됩니다. 계획 지침에 대한 자세한 내용은 계획 지침 이해를 참조하십시오.
주의 |
---|
쿼리 힌트를 오용하는 계획 지침을 사용하면 컴파일, 실행 또는 성능 문제가 발생할 수 있습니다. 계획 지침은 숙련된 개발자와 데이터베이스 관리자만 사용해야 합니다. |
INDEX 및 FORCESEEK 테이블 힌트를 쿼리 힌트로 지정하는 경우 다음 개체에 대해서 유효합니다.
테이블
뷰
인덱싱된 뷰
공통 테이블 식. 공통 테이블 식을 채울 결과 집합이 있는 SELECT 문에 힌트를 지정해야 합니다.
동적 관리 뷰
명명된 하위 쿼리
테이블 힌트는 테이블 반환 함수, 테이블 변수 또는 OPENROWSET 문에 대해 지정할 수 없습니다.
인덱싱된 뷰에 대해 인덱스 힌트를 지정하려면 NOEXPAND 힌트도 OPTION 절에 지정해야 하며 그렇지 않으면 인덱스 힌트가 무시됩니다. 자세한 내용은 뷰의 인덱스 확인을 참조하십시오.
INDEX 및 FORCESEEK 힌트를 쿼리 힌트로 지정하는 데 사용되는 구문에 대한 자세한 내용은 쿼리 힌트(Transact-SQL)를 참조하십시오.
최선의 구현 방법
다음과 같은 최선의 구현 방법을 권장합니다.
계획 지침 문을 테스트할 때 계획 지침 또는 임시 쿼리 컨텍스트에서만 INDEX 및 FORCESEEK 힌트를 쿼리 힌트로 사용합니다. 다른 모든 임시 쿼리의 경우에는 이러한 힌트를 테이블 힌트로 지정합니다.
FORCESEEK 힌트를 사용하기 전에 데이터베이스의 통계가 현재 통계이며 정확한지 확인합니다.
최적화 프로그램에서는 최신 통계를 통해 다양한 쿼리 계획의 비용을 정확하게 평가하고 우수한 계획을 선택할 수 있습니다. 따라서 모든 사용자 데이터베이스에 대해 AUTO_CREATE_STATISTICS 및 AUTO_UPDATE_STATISTICS를 ON(기본값)으로 설정하는 것이 좋습니다. 또는 UPDATE STATISTICS 문을 사용하여 테이블이나 뷰의 통계를 수동으로 업데이트할 수 있습니다.
INDEX 힌트를 FORCESEEK와 함께 불필요하게 사용하지 않습니다. 즉, FORCESEEK만 사용해도 충분한 계획이 생성되는 경우 INDEX 힌트를 사용하면 최적화 프로그램의 선택 사항을 과도하게 제한할 수 있습니다. 또한 테이블의 물리적 스키마를 변경하여 힌트에 지정된 인덱스를 제거하는 경우 INDEX 힌트로 인해 쿼리가 실패할 수 있습니다. 반대로 FORCESEEK 힌트가 적용된 테이블에 사용 가능한 인덱스가 하나 이상 있는 동안은 인덱스 구조를 변경하더라도 쿼리가 컴파일됩니다.
INDEX 힌트 INDEX (0)을 FORCESEEK 힌트와 함께 사용하지 않습니다. INDEX (0)은 기본 테이블의 검색을 강제로 실행합니다. FORCESEEK와 함께 사용하면 계획이 검색되지 않으며 오류 8622가 반환됩니다.
USE PLAN 쿼리 힌트를 FORCESEEK 힌트와 함께 사용하지 않습니다. 함께 사용하면 FORCESEEK 힌트가 무시됩니다.
INDEX 및 FORCESEEK 힌트를 다른 테이블 힌트와 함께 사용
기존 테이블 힌트가 없는 쿼리에 대해 INDEX 및 FORCESEEK 힌트를 지정할 수 있습니다. 또는 INDEX 및 FORCESEEK 힌트를 사용하여 쿼리에 있는 기존 INDEX 및 FORCESEEK 힌트를 하나 이상 대체할 수 있습니다. 계획 지침과 일치하는 쿼리에 이러한 테이블 힌트를 지정하는 WITH 절이 이미 있는 경우 계획 지침의 @hints 매개 변수에 지정된 힌트가 쿼리에 있는 해당 힌트를 대체합니다. 예를 들어 쿼리에 HumanResources.Employee 테이블에 대한 테이블 힌트 WITH INDEX (PK_Employee_EmployeeID)가 있고 계획 지침의 @hints 매개 변수가 OPTION (TABLE HINT ( HumanResources.Employee, INDEX( IX_Employee_ManagerID ) )를 지정하면 쿼리 최적화 프로그램이 IX_Employee_ManagerID 인덱스를 사용합니다.
쿼리에 테이블 힌트를 지정하는 WITH 절이 없다면 INDEX 및 FORCESEEK 이외의 테이블 힌트를 계획 지침의 쿼리 힌트로 사용할 수 없습니다. 이 경우 OPTION 절에 TABLE HINT를 사용하여 일치하는 힌트를 쿼리 힌트로 지정함으로써 쿼리의 의미 체계를 유지해야 합니다. 예를 들어 쿼리에 테이블 힌트 NOLOCK이 있는 경우 계획 지침의 @hints 매개 변수에도 NOLOCK 힌트가 있어야 하며 OPTION 절에도 INDEX 또는 FORCESEEK 테이블 힌트가 있어야 합니다. 이 항목의 뒷부분에 나오는 예 3을 참조하십시오. 일치하는 쿼리 힌트 없이 OPTION 절에 TABLE HINT를 사용하여 INDEX 또는 FORCESEEK 이외의 테이블 힌트를 지정하거나 그 반대의 경우 OPTION 절로 인해 쿼리의 의미 체계가 변경되고 쿼리가 실패할 수 있음을 나타내는 오류 8702가 발생합니다.
INDEX 및 FORCESEEK 힌트를 다른 쿼리 힌트와 함께 사용
계획 지침과 일치하는 쿼리에 쿼리 힌트를 지정하는 OPTION 절이 이미 있는 경우 계획 지침의 @hints 매개 변수에 지정된 쿼리 힌트가 쿼리에 있는 해당 힌트를 대체합니다. 그러나 계획 지침이 OPTION 절이 이미 있는 쿼리와 일치하려면 sp_create_plan_guide(Transact-SQL) 문에서 일치하는 쿼리의 텍스트를 지정할 때 쿼리의 OPTION 절을 포함해야 합니다. 계획 지침에 지정한 힌트로 쿼리에 이미 있는 힌트를 대체하는 대신 계획 지침에 지정한 힌트를 쿼리에 이미 있는 힌트에 추가하려면 원래 힌트와 추가 힌트를 모두 계획 지침의 OPTION 절에 지정해야 합니다.
예
1. FORCESEEK 사용
다음 예에서는 계획 지침의 @hints 매개 변수에 FORCESEEK 힌트를 사용합니다. 이 옵션은 최적화 프로그램이 Index Seek 연산을 사용하여 HumanResources.Employee 테이블에 있는 데이터에 액세스하도록 합니다. 이렇게 하면 최적화 프로그램이 테이블 힌트에 지정된 인덱스 이외의 인덱스를 사용할 수 있습니다.
USE AdventureWorks;
GO
EXEC sp_create_plan_guide
@name = N'Guide3',
@stmt = N'SELECT c.LastName, c.FirstName, HumanResources.Employee.Title
FROM HumanResources.Employee
JOIN Person.Contact AS c ON HumanResources.Employee.ContactID = c.ContactID
WHERE HumanResources.Employee.ManagerID = 3
ORDER BY c.LastName, c.FirstName;',
@type = N'SQL',
@module_or_batch = NULL,
@params = NULL,
@hints = N'OPTION (TABLE HINT( HumanResources.Employee, FORCESEEK))';
GO
2. 여러 테이블 힌트 사용
다음 예에서는 한 테이블에 INDEX 힌트를 적용하고 다른 테이블에 FORCESEEK 힌트를 적용합니다.
USE AdventureWorks;
GO
EXEC sp_create_plan_guide
@name = N'Guide4',
@stmt = N'SELECT e.ManagerID, c.LastName, c.FirstName, e.Title
FROM HumanResources.Employee AS e
JOIN Person.Contact AS c ON e.ContactID = c.ContactID
WHERE e.ManagerID = 3;',
@type = N'SQL',
@module_or_batch = NULL,
@params = NULL,
@hints = N'OPTION (TABLE HINT ( e, INDEX( IX_Employee_ManagerID ) )
, TABLE HINT ( c, FORCESEEK) )';
GO
3. 의미 체계에 영향을 주는 힌트 지정
다음 예의 쿼리에는 두 가지 테이블 힌트가 포함되어 있습니다. 하나는 의미 체계에 영향을 주는 NOLOCK이고 다른 하나는 의미 체계에 영향을 주지 않는 INDEX입니다. 쿼리의 의미 체계를 유지하기 위해 계획 지침의 OPTIONS 절에 NOLOCK 힌트가 지정됩니다. NOLOCK 힌트 외에 INDEX 및 FORCESEEK 힌트가 지정되고 문을 컴파일 및 최적화할 때 쿼리에서 의미 체계에 영향을 주지 않는 INDEX 힌트를 대체합니다.
USE AdventureWorks;
GO
EXEC sp_create_plan_guide
@name = N'Guide6',
@stmt = N'SELECT c.LastName, c.FirstName, e.Title
FROM HumanResources.Employee AS e
WITH (NOLOCK, INDEX (PK_Employee_EmployeeID))
JOIN Person.Contact AS c ON e.ContactID = c.ContactID
WHERE e.ManagerID = 3;',
@type = N'SQL',
@module_or_batch = NULL,
@params = NULL,
@hints = N'OPTION (TABLE HINT ( e, INDEX( IX_Employee_ManagerID) , NOLOCK, FORCESEEK ))';
GO
다음 예에서는 쿼리의 의미 체계를 유지하며 최적화 프로그램이 테이블 힌트에 지정된 인덱스 이외의 인덱스를 선택할 수 있도록 하는 대체 방법을 보여 줍니다. 이 작업은 의미 체계에 영향을 주는 NOLOCK 힌트를 OPTIONS 절에 지정하고 테이블 참조만 있고 INDEX 힌트는 없는 TABLE HINT 키워드를 지정하여 수행됩니다.
USE AdventureWorks;
GO
EXEC sp_create_plan_guide
@name = N'Guide7',
@stmt = N'SELECT c.LastName, c.FirstName, e.Title
FROM HumanResources.Employee AS e
WITH (NOLOCK, INDEX (PK_Employee_EmployeeID))
JOIN Person.Contact AS c ON e.ContactID = c.ContactID
WHERE e.ManagerID = 2;',
@type = N'SQL',
@module_or_batch = NULL,
@params = NULL,
@hints = N'OPTION (TABLE HINT ( e, NOLOCK))';
GO
4. TABLE HINT를 사용하여 기존 테이블 힌트 덮어쓰기
다음 예에서는 INDEX 힌트를 지정하지 않고 TABLE HINT를 사용하여 쿼리의 FROM 절에 지정된 INDEX 테이블 힌트의 동작을 덮어쓰는 방법을 보여 줍니다. 이 방법을 사용하면 최적화 프로그램이 테이블 힌트에 지정된 인덱스 이외의 인덱스를 선택할 수 있습니다.
USE AdventureWorks;
GO
EXEC sp_create_plan_guide
@name = N'Guide5',
@stmt = N'SELECT e.ManagerID, c.LastName, c.FirstName, e.Title
FROM HumanResources.Employee AS e WITH (INDEX (IX_Employee_ManagerID))
JOIN Person.Contact AS c ON e.ContactID = c.ContactID
WHERE e.ManagerID = 3;',
@type = N'SQL',
@module_or_batch = NULL,
@params = NULL,
@hints = N'OPTION (TABLE HINT(e))';
GO