테이블 힌트(Transact-SQL)
적용 대상: Microsoft Fabric의 SQL ServerAzure SQL Database Azure SQL Managed InstanceSQL 데이터베이스
테이블 힌트는 DML(데이터 조작 언어) 문 중에 쿼리 최적화 프로그램의 기본 동작을 재정의하는 데 사용됩니다. 잠금 메서드, 하나 이상의 인덱스, 쿼리 처리 작업(예: 테이블 검색 또는 인덱스 찾기) 또는 기타 옵션을 지정할 수 있습니다. 테이블 힌트는 DML 문의 FROM
절에 지정되며 해당 절에서 참조되는 테이블 또는 뷰에만 영향을 줍니다.
주의
일반적으로 SQL Server 쿼리 최적화 프로그램은 쿼리에 대해 최상의 실행 계획을 선택하므로 숙련된 개발자 및 데이터베이스 관리자가 마지막 방법으로만 힌트를 사용하는 것이 좋습니다.
적용 대상:
구문
WITH ( <table_hint> [ [ , ] ...n ] )
<table_hint> ::=
{ NOEXPAND
| INDEX ( <index_value> [ , ...n ] ) | INDEX = ( <index_value> )
| FORCESEEK [ ( <index_value> ( <index_column_name> [ , ... ] ) ) ]
| FORCESCAN
| HOLDLOCK
| NOLOCK
| NOWAIT
| PAGLOCK
| READCOMMITTED
| READCOMMITTEDLOCK
| READPAST
| READUNCOMMITTED
| REPEATABLEREAD
| ROWLOCK
| SERIALIZABLE
| SNAPSHOT
| SPATIAL_WINDOW_MAX_CELLS = <integer_value>
| TABLOCK
| TABLOCKX
| UPDLOCK
| XLOCK
}
<table_hint_limited> ::=
{
KEEPIDENTITY
| KEEPDEFAULTS
| HOLDLOCK
| IGNORE_CONSTRAINTS
| IGNORE_TRIGGERS
| NOLOCK
| NOWAIT
| PAGLOCK
| READCOMMITTED
| READCOMMITTEDLOCK
| READPAST
| REPEATABLEREAD
| ROWLOCK
| SERIALIZABLE
| SNAPSHOT
| TABLOCK
| TABLOCKX
| UPDLOCK
| XLOCK
}
인수
WITH ( <table_hint> ) [ [ , ] ...n ]
일부 예외를 제외하고 FROM
절에서 WITH
키워드로 힌트를 지정한 경우에만 테이블 힌트가 지원됩니다. 또한 테이블 힌트는 괄호로 묶어 지정해야 합니다.
Important
WITH
키워드를 생략하는 것은 사용되지 않는 기능입니다. 이 기능은 이후 버전의 SQL Server에서 제거됩니다. 새 개발 작업에서는 이 기능을 사용하지 않도록 하고, 현재 이 기능을 사용하는 애플리케이션은 수정하세요.
다음 테이블 힌트는 WITH
키워드를 포함하거나 포함하지 않고 사용할 수 있습니다. NOLOCK
, READUNCOMMITTED
, UPDLOCK
, REPEATABLEREAD
, SERIALIZABLE
, READCOMMITTED
, TABLOCK
, TABLOCKX
, PAGLOCK
, ROWLOCK
, NOWAIT
, READPAST
, XLOCK
, SNAPSHOT
, NOEXPAND
이러한 테이블 힌트를 WITH
키워드 없이 지정하는 경우 힌트를 단독으로 지정해야 합니다. 다음은 그 예입니다.
FROM t (TABLOCK)
힌트를 다른 옵션으로 지정하면 WITH
키워드를 사용하여 힌트를 지정해야 합니다.
FROM t WITH (TABLOCK, INDEX(myindex))
테이블 힌트 사이에는 쉼표를 사용하는 것이 좋습니다.
Important
힌트를 쉼표가 아닌 공백으로 구분하는 기능은 사용되지 않는 기능입니다. 이 기능은 이후 버전의 SQL Server에서 제거됩니다. 새 개발 작업에서는 이 기능을 사용하지 않도록 하고, 현재 이 기능을 사용하는 애플리케이션은 수정하세요.
NOEXPAND
쿼리 최적화 프로그램에서 쿼리를 처리할 때 기본 테이블에 액세스하기 위해 인덱싱된 뷰를 확장하지 않도록 지정합니다. 쿼리 최적화 프로그램은 뷰를 클러스터형 인덱스가 있는 테이블처럼 처리합니다.
NOEXPAND
는 인덱싱된 뷰에만 적용됩니다. 자세한 내용은 NOEXPAND사용
INDEX ( <index_value> [ , ...n ] ) | INDEX = ( <index_value> )
INDEX()
구문은 쿼리 최적화 프로그램이 문을 처리할 때 사용할 인덱스 하나 이상의 이름이나 ID를 지정합니다. 대체 INDEX =
구문은 단일 인덱스 값을 지정합니다. 테이블당 하나의 인덱스 힌트만 지정할 수 있습니다.
클러스터형 인덱스가 있는 경우에는 INDEX(0)
이 클러스터형 인덱스 검색을 강제 실행하고 INDEX(1)
이 클러스터형 인덱스 검색 또는 찾기를 강제 실행합니다. 클러스터형 인덱스가 없는 경우 INDEX(0)
은 테이블 검색을 강제 실행하고 INDEX(1)
은 오류로 해석됩니다.
단일 힌트 목록에서 여러 인덱스가 사용되는 경우에는 중복이 무시되고 나열된 인덱스 중 나머지를 사용하여 테이블의 행을 검색합니다. 이때 인덱스 힌트에 있는 인덱스의 순서가 중요합니다. 여러 인덱스 힌트는 또한 인덱스 AND 연산을 강제 실행하고 쿼리 최적화 프로그램은 액세스되는 각 인덱스에 대해 가능한 한 많은 조건을 적용합니다. 인덱스 힌트 컬렉션에 쿼리에서 참조하는 모든 열이 포함되지 않은 경우 SQL Server 데이터베이스 엔진이 모든 인덱싱된 열을 검색한 후 페치를 수행하여 남은 열을 검색합니다.
참고
여러 인덱스를 참조하는 인덱스 힌트가 스타 조인의 팩트 테이블에 사용되는 경우 최적화 프로그램은 인덱스 힌트를 무시하고 경고 메시지를 반환합니다. 또한 인덱스 힌트가 지정된 테이블에는 인덱스 ORing이 허용되지 않습니다.
테이블 힌트의 최대 인덱스 수는 비클러스터형 인덱스 250개입니다.
KEEPIDENTITY
BULK
옵션을 OPENROWSET사용하는 경우에만 INSERT
문에 적용할 수 있습니다.
가져온 데이터 파일의 ID 값이 ID 열에 사용되도록 지정합니다.
KEEPIDENTITY
지정되지 않은 경우 이 열의 ID 값은 확인되지만 가져오지 않으며 쿼리 최적화 프로그램은 테이블을 만드는 동안 지정된 시드 및 증가 값에 따라 고유 값을 자동으로 할당합니다.
Important
데이터 파일에 테이블 또는 뷰의 ID 열에 대한 값이 없고 ID 열이 테이블의 마지막 열이 아닌 경우 ID 열을 건너뛰어야 합니다. 자세한 내용은 서식 파일을 사용하여 데이터 필드(SQL Server)건너뛰기를 참조하세요. ID 열을 성공적으로 건너뛰면 쿼리 최적화 프로그램은 가져온 테이블 행에 ID 열의 고유 값을 자동으로 할당합니다.
INSERT ... SELECT * FROM OPENROWSET(BULK...)
문에서 이 힌트를 사용하는 예제는 데이터 대량 가져오기(SQL Server)때 ID 값 유지를 참조하세요.
테이블의 ID 값을 확인하는 방법에 대한 자세한 내용은 DBCC CHECKIDENT참조하세요.
KEEPDEFAULTS
BULK
옵션을 OPENROWSET사용하는 경우에만 INSERT
문에 적용할 수 있습니다.
데이터 레코드에 열 값이 없을 때 NULL
대신 테이블 열의 기본값(있는 경우)의 삽입을 지정합니다.
INSERT ... SELECT * FROM OPENROWSET(BULK...)
문에서 이 힌트를 사용하는 예제는 대량 가져오기(SQL Server)동안 null 또는 기본값 유지를 참조하세요.
FORCESEEK [ ( <index_value> ( <index_column_name> [ , ...n ] ) ) ]
쿼리 최적화 프로그램이 테이블 또는 뷰의 데이터에 대한 액세스 경로로 인덱스 찾기 작업만 사용하도록 지정합니다.
참고
SQL Server 2008 R2(10.50.x) 서비스 팩 1부터는 인덱스 매개 변수도 지정할 수 있습니다. 이 경우 쿼리 최적화 프로그램이 최소 지정된 인덱스 열을 사용하여 지정된 인덱스 전체에서 Index Seek 연산만 고려합니다.
index_value
인덱스 이름 또는 인덱스 ID 값입니다. 인덱스 ID 0(힙)은 지정할 수 없습니다. 인덱스 이름 또는 ID를 반환하려면
sys.indexes
카탈로그 뷰를 쿼리합니다.index_column_name
찾기 작업에 포함하려는 인덱스 열의 이름입니다. 인덱스 매개 변수와 함께
FORCESEEK
를 지정하는 것은FORCESEEK
힌트와 함께INDEX
를 사용하는 것과 비슷합니다. 그러나 검색할 인덱스와 Seek 연산에서 고려하는 인덱스 열을 모두 지정하여 쿼리 최적화 프로그램에 사용되는 액세스 경로를 더 많이 제어할 수 있습니다. 최적화 프로그램은 필요한 경우 더 많은 열을 고려할 수 있습니다. 예를 들어 비클러스터형 인덱스를 지정하면 최적화 프로그램에서 지정된 열 외에도 클러스터형 인덱스 키 열을 사용하도록 선택할 수 있습니다.
FORCESEEK
는 다음 방법으로 지정할 수 있습니다.
구문 | 예제 | 설명 |
---|---|---|
인덱스 또는 INDEX 힌트 없이 사용 |
FROM dbo.MyTable WITH (FORCESEEK) |
쿼리 최적화 프로그램이 Index Seek 연산만 고려하여 모든 관련 인덱스 전체에서 테이블 또는 뷰에 액세스합니다. |
INDEX 힌트와 함께 사용 |
FROM dbo.MyTable WITH (FORCESEEK, INDEX (MyIndex)) |
쿼리 최적화 프로그램이 Index Seek 연산만 고려하여 지정된 인덱스 전체에서 테이블 또는 뷰에 액세스합니다. |
인덱스 및 인덱스 열을 지정하여 매개 변수 있음 | FROM dbo.MyTable WITH (FORCESEEK (MyIndex (col1, col2, col3))) |
쿼리 최적화 프로그램이 최소 지정된 인덱스 열을 사용하여 지정된 인덱스 전체에서 Index Seek 연산만 고려하여 테이블 또는 뷰에 액세스합니다. |
FORCESEEK
힌트(인덱스 매개 변수 사용 또는 사용 안 함)를 사용할 경우 다음 지침을 고려합니다.
- 힌트는 테이블 힌트 또는 쿼리 힌트로 지정될 수 있습니다. 쿼리 힌트에 대한 자세한 내용은 쿼리 힌트(Transact-SQL)참조하세요.
-
FORCESEEK
를 인덱싱된 뷰에 적용하려면NOEXPAND
힌트도 지정해야 합니다. - 힌트는 테이블 또는 뷰마다 최대 한 번 적용될 수 있습니다.
- 원격 데이터 원본에 대해서는 힌트를 지정할 수 없습니다. 오류 7377은
FORCESEEK
가 인덱스 힌트와 함께 지정될 때 반환되고 오류 8180은FORCESEEK
가 인덱스 힌트 없이 사용될 때 반환됩니다. -
FORCESEEK
계획이 없으면 오류 8622가 반환됩니다.
FORCESEEK
가 인덱스 매개 변수와 함께 지정된 경우 다음 지침과 제한 사항이 적용됩니다.
-
INSERT
,UPDATE
또는DELETE
문의 대상인 테이블에 대한 힌트를 지정할 수 없습니다. - 힌트는
INDEX
힌트 또는 또 다른FORCESEEK
힌트와 함께 지정할 수 없습니다. - 최소 하나의 열이 지정되어야 하고 선행 키 열이어야 합니다.
- 추가 인덱스 열을 지정할 수 있지만 키 열은 건너뛸 수 없습니다. 예를 들어 지정된 인덱스가 키 열을 포함할 경우
a
,b
,c
및 유효한 구문은FORCESEEK (MyIndex (a))
및FORCESEEK (MyIndex (a, b)
를 포함합니다. 유효하지 않은 구문은FORCESEEK (MyIndex (c))
및FORCESEEK (MyIndex (a, c)
를 포함합니다. - 힌트에서 지정한 열 이름 순서는 반드시 참조된 인덱스에 있는 열 순서와 일치해야 합니다.
- 인덱스 키 정의에 없는 열은 지정할 수 없습니다. 예를 들어 비클러스터형 인덱스에서는 정의된 인덱스 키 열만 지정할 수 있습니다. 인덱스에 자동으로 포함되는 클러스터형 키 열은 지정할 수 없지만 최적화 프로그램에서 사용할 수 있습니다.
- xVelocity 메모리 최적화 columnstore 인덱스는 인덱스 매개 변수로 지정할 수 없습니다. 오류 366이 반환됩니다.
- 예를 들어 열을 추가하거나 제거하여 인덱스 정의를 수정하려면 해당 인덱스를 참조하는 쿼리를 수정해야 할 수 있습니다.
- 힌트는 최적화 프로그램이 테이블의 모든 공간 또는 XML 인덱스를 고려하지 않도록 합니다.
- 힌트는
FORCESCAN
힌트와 함께 지정할 수 없습니다. - 분할된 인덱스의 경우 SQL Server에서 암시적으로 추가된 분할 열은
FORCESEEK
힌트에 지정할 수 없습니다.
주의
매개 변수와 함께 FORCESEEK
를 지정할 경우 매개 변수 없이 FORCESEEK
를 지정할 때보다 최적화 프로그램에서 고려할 수 있는 계획 수가 더 제한됩니다. 이로 인해 더 많은 경우에 Plan cannot be generated
오류가 발생할 수 있습니다.
FORCESCAN
적용 대상: SQL Server 2008 R2(10.50.x) 서비스 팩 1 이상 버전
쿼리 최적화 프로그램이 참조된 테이블 또는 뷰의 액세스 경로로 인덱스 검색 작업만 사용하도록 지정합니다.
FORCESCAN
힌트는 최적화 프로그램이 영향을 받는 행의 수를 과소 평가하고 검색 작업 대신 찾기 작업을 선택하는 경우 쿼리에 유용할 수 있습니다. 이 경우 작업에 할당되는 메모리 양이 적으며 쿼리 성능에도 영향을 줍니다.
FORCESCAN
은 INDEX
힌트와 함께 또는 이 힌트 없이 지정할 수 있습니다. 인덱스 힌트(INDEX = index_name, FORCESCAN
)와 결합된 경우 쿼리 최적화 프로그램은 참조된 테이블에 액세스할 때 지정된 인덱스를 통해 액세스 경로 검색만 고려합니다. 기본 테이블에 대해 테이블 검색 작업이 강제로 수행되도록 하기 위해 FORCESCAN
을 인덱스 힌트 INDEX(0)
과 함께 지정할 수 없습니다.
분할된 테이블 및 인덱스의 경우 쿼리 조건자 평가를 통해 파티션이 제거된 후 FORCESCAN
적용됩니다. 즉, 검색은 전체 테이블이 아니라 나머지 파티션에만 적용됩니다.
FORCESCAN
힌트에는 다음 제한 사항이 있습니다.
-
INSERT
,UPDATE
또는DELETE
문의 대상인 테이블에 대한 힌트를 지정할 수 없습니다. - 힌트를 두 개 이상의 인덱스 힌트와 함께 사용할 수 없습니다.
- 힌트는 쿼리 최적화 프로그램이 테이블의 모든 공간 또는 XML 인덱스를 고려하지 않도록 합니다.
- 원격 데이터 원본에 대해서는 힌트를 지정할 수 없습니다.
- 힌트는
FORCESEEK
힌트와 함께 지정할 수 없습니다.
HOLDLOCK
SERIALIZABLE
과 동일합니다. 자세한 내용은 이 문서의 뒷부분에 나오는 serializable HOLDLOCK
지정된 테이블 또는 뷰에만 적용되며 사용된 문으로 정의된 트랜잭션 기간 동안에만 적용됩니다.
HOLDLOCK
옵션을 포함하는 SELECT 문에는 FOR BROWSE
을 사용할 수 없습니다.
IGNORE_CONSTRAINTS
BULK
옵션을 OPENROWSET사용하는 경우에만 INSERT
문에 적용할 수 있습니다.
대량 가져오기 작업이 테이블에 대한 제약 조건을 무시함을 지정합니다. 기본적으로 IGNORE_CONSTRAINTS
지정되면 INSERT
대상 테이블에서 이러한 제약 조건을 무시해야 합니다.
UNIQUE
, PRIMARY KEY
또는 NOT NULL
제약 조건을 사용하지 않도록 설정할 수 없습니다.
입력 데이터에 제약 조건을 위반하는 행이 포함된 경우 CHECK
및 FOREIGN KEY
제약 조건을 사용하지 않도록 설정할 수 있습니다.
CHECK
및 FOREIGN KEY
제약 조건을 사용하지 않도록 설정하면 데이터를 가져온 다음 Transact-SQL 문을 사용하여 데이터를 정리할 수 있습니다.
그러나 CHECK
및 FOREIGN KEY
제약 조건이 무시되면 테이블에서 무시된 각 제약 조건은 작업 후 sys.check_constraints 또는 sys.foreign_keys 카탈로그 뷰에서 is_not_trusted
표시됩니다. 어느 시점에서는 전체 테이블의 제약 조건을 확인해야 합니다. 대량 가져오기 작업 전에 테이블이 비어 있지 않은 경우 제약 조건을 다시 적용하는 비용이 증분 데이터에 CHECK
및 FOREIGN KEY
제약 조건을 적용하는 비용을 초과할 수 있습니다.
IGNORE_TRIGGERS
BULK
옵션을 OPENROWSET사용하는 경우에만 INSERT
문에 적용할 수 있습니다.
대량 가져오기 작업에서 테이블에 정의된 모든 트리거를 무시하도록 지정합니다. 기본적으로 INSERT
트리거를 적용합니다.
애플리케이션이 트리거에 의존하지 않고 성능 극대화가 중요한 경우에만 IGNORE_TRIGGERS
사용합니다.
NOLOCK
READUNCOMMITTED
과 동일합니다. 자세한 내용은 이 문서의 뒷부분에 READUNCOMMITTED 참조하세요.
참고
UPDATE
또는 DELETE
문의 경우: 이 기능은 이후 버전의 SQL Server에서 제거됩니다. 새 개발 작업에서는 이 기능을 사용하지 않도록 하고, 현재 이 기능을 사용하는 애플리케이션은 수정하세요.
NOWAIT
테이블에 잠금이 있으면 데이터베이스 엔진에서 바로 메시지를 반환하도록 지정합니다.
NOWAIT
는 특정 테이블에 대한 SET LOCK_TIMEOUT 0
힌트를 지정하는 것과 같습니다.
NOWAIT
힌트도 포함된 경우에는 TABLOCK
힌트가 작동하지 않습니다.
TABLOCK
힌트를 사용할 때 기다리지 않고 쿼리를 종료하려면 쿼리 앞에 SET LOCK_TIMEOUT 0;
을 대신 추가합니다.
PAGLOCK
일반적으로 행 또는 키에 개별 잠금이 사용되거나 일반적으로 단일 테이블 잠금이 사용되는 곳에서 페이지 잠금을 사용합니다. 기본적으로 작업에 적합한 잠금 모드를 사용합니다.
SNAPSHOT
격리 수준에서 작동하는 트랜잭션에 지정하는 경우 PAGLOCK
및 UPDLOCK
과 같은 잠금이 필요한 다른 테이블 힌트와 함께 HOLDLOCK
을 사용하지 않으면 페이지 잠금이 수행되지 않습니다.
READCOMMITTED
읽기 작업이 잠금 또는 행 버전 관리를 사용하여 READ COMMITTED
격리 수준에 대한 규칙을 준수하게 지정합니다. 데이터베이스 옵션 READ_COMMITTED_SNAPSHOT
OFF
경우 데이터베이스 엔진은 데이터를 읽을 때 공유 잠금을 획득하고 읽기 작업이 완료되면 해당 잠금을 해제합니다. 데이터베이스 옵션 READ_COMMITTED_SNAPSHOT
ON
경우 데이터베이스 엔진은 잠금을 획득하지 않고 행 버전 관리 사용을 사용합니다. 격리 수준에 대한 자세한 내용은 SET TRANSACTION ISOLATION LEVEL참조하세요.
참고
UPDATE
또는 DELETE
문의 경우: 이 기능은 이후 버전의 SQL Server에서 제거됩니다. 새 개발 작업에서는 이 기능을 사용하지 않도록 하고, 현재 이 기능을 사용하는 애플리케이션은 수정하세요.
READCOMMITTEDLOCK
읽기 작업이 잠금을 사용하여 READ COMMITTED
격리 수준에 대한 규칙을 준수하게 지정합니다. 데이터베이스 엔진은 READ_COMMITTED_SNAPSHOT
데이터베이스 옵션의 설정에 관계없이 데이터를 읽을 때 공유 잠금을 획득하고 읽기 작업이 완료되면 잠금을 해제합니다. 격리 수준에 대한 자세한 내용은 SET TRANSACTION ISOLATION LEVEL참조하세요. 이 힌트는 INSERT
문의 대상 테이블에 지정할 수 없습니다. 오류 4140이 반환됩니다.
READPAST
데이터베이스 엔진이 다른 트랜잭션에 의해 잠긴 행을 읽지 않도록 지정합니다.
READPAST
가 지정되면 행 수준 잠금은 건너뛰지만, 페이지 수준 잠금은 건너뛰지 않습니다. 즉, 데이터베이스 엔진은 잠금이 해제될 때까지 현재 트랜잭션을 차단하는 대신 행을 건너뜁니다. 예를 들어 T1
테이블에 값이 1, 2, 3, 4, 5인 단일 정수 열이 있다고 가정합니다. 트랜잭션 A가 값을 3에서 8로 변경하지만 아직 커밋되지 않은 경우 값 1, SELECT * FROM T1 (READPAST)
2, 4, 5를 생성합니다.
READPAST
는 주로 SQL Server 테이블을 사용하는 작업 큐를 구현할 때 잠금 경합을 줄이는 데 사용됩니다.
READPAST
를 사용하는 큐 판독기는 다른 트랜잭션에 의해 잠긴 큐 항목이 있으면 다른 트랜잭션이 잠금을 해제할 때까지 기다리지 않고 사용 가능한 다음 큐 항목으로 건너뜁니다.
READPAST
UPDATE
또는 DELETE
문에서 참조되는 테이블과 FROM
절에서 참조되는 테이블에 대해 지정할 수 있습니다.
UPDATE
문에 지정된 경우 READPAST
지정된 문의 위치에 관계없이 업데이트할 레코드를 식별하기 위해 데이터를 읽을 때만 적용됩니다.
READPAST
INSERT
문의 INTO
절에 있는 테이블에 대해 지정할 수 없습니다. 외장 키 또는 인덱싱된 뷰를 읽거나 보조 인덱스를 수정할 때 READPAST
사용하는 업데이트 또는 삭제 작업이 차단될 수 있습니다.
READPAST
READ COMMITTED
또는 REPEATABLE READ
격리 수준에서 작동하는 트랜잭션에서만 지정할 수 있습니다.
SNAPSHOT
격리 수준에서 작동하는 트랜잭션에 지정하는 경우 READPAST
및 UPDLOCK
과 같은 잠금이 필요한 다른 테이블 힌트와 함께 HOLDLOCK
를 사용해야 합니다.
READ_COMMITTED_SNAPSHOT
데이터베이스 옵션이 ON
설정되고 다음 조건 중 하나가 true이면 READPAST
테이블 힌트를 지정할 수 없습니다.
- 세션의 트랜잭션 격리 수준이
READ COMMITTED
. -
READCOMMITTED
테이블 힌트가 쿼리에도 지정되어 있습니다.
이러한 경우 READPAST
힌트를 지정하려면 READCOMMITTED
테이블 힌트가 있으면 이를 제거하고 쿼리에 READCOMMITTEDLOCK
테이블 힌트를 포함합니다.
READUNCOMMITTED
더티 읽기를 허용하도록 지정합니다. 다른 트랜잭션이 현재 트랜잭션의 데이터 읽기를 수정하지 못하도록 하는 공유 잠금이 실행되지 않으며 다른 트랜잭션에 의해 설정된 배타적 잠금은 현재 트랜잭션의 잠긴 데이터 읽기를 차단하지 않습니다. 더티 읽기를 허용하면 동시성이 높아질 수 있지만 다른 트랜잭션이 데이터 수정 내용을 읽고 롤백할 가능성이 있습니다. 이렇게 하면 트랜잭션에 대한 오류가 생성되거나, 커밋되지 않은 데이터가 사용자에게 표시되거나, 사용자가 레코드를 두 번(또는 전혀 볼 수 없음) 발생할 수 있습니다.
READUNCOMMITTED
및 NOLOCK
힌트는 데이터 잠금에만 적용됩니다.
READUNCOMMITTED
및 NOLOCK
힌트가 있는 쿼리를 비롯한 모든 쿼리는 컴파일 및 실행 중에 Sch-S(스키마 안정성) 잠금을 획득합니다. 이 때문에 동시 트랜잭션이 테이블에 대해 Sch-M(스키마 수정) 잠금을 유지하면 쿼리가 차단됩니다. 예를 들어 DDL(데이터 정의 언어) 작업은 테이블의 스키마 정보를 수정하기 전에 Sch-M 잠금을 획득합니다.
READUNCOMMITTED
또는 NOLOCK
힌트로 실행되는 쿼리를 비롯한 모든 동시 쿼리는 Sch-S 잠금을 획득하려고 할 때 차단됩니다. 반대로 Sch-S 잠금을 유지하는 쿼리는 Sch-M 잠금을 획득하려고 시도하는 동시 트랜잭션을 차단합니다.
삽입, 업데이트 또는 삭제 작업으로 수정된 테이블에 대해서는 READUNCOMMITTED
및 NOLOCK
을 지정할 수 없습니다. SQL Server 쿼리 최적화 프로그램은 UPDATE
또는 DELETE
문의 대상 테이블에 적용되는 FROM
절의 READUNCOMMITTED
및 NOLOCK
힌트를 무시합니다.
참고
UPDATE
또는 DELETE
문의 대상 테이블에 적용되는 FROM
절의 READUNCOMMITTED
및 NOLOCK
힌트 사용에 대한 지원은 이후 버전의 SQL Server에서 제거됩니다. 새 개발 작업에서는 이 컨텍스트에서 이러한 힌트를 사용하지 않도록 하고 현재 이 힌트를 사용하는 애플리케이션은 수정하세요.
다음 옵션 중 하나를 사용하여 커밋되지 않은 데이터 수정의 더티 읽기로부터 트랜잭션을 보호하면서 잠금 경합을 최소화할 수 있습니다.
-
READ_COMMITTED_SNAPSHOT
데이터베이스 옵션이ON
설정된READ COMMITTED
격리 수준입니다. -
SNAPSHOT
격리 수준입니다.
격리 수준에 대한 자세한 내용은 SET TRANSACTION ISOLATION LEVEL참조하세요.
참고
READUNCOMMITTED
지정될 때 오류 메시지 601 수신하는 경우 교착 상태 오류(오류 메시지 1205)와 마찬가지로 해결한 다음 문을 다시 시도합니다.
REPEATABLEREAD
REPEATABLE READ
격리 수준에서 실행되는 트랜잭션과 동일한 잠금 의미 체계를 사용하여 검사를 수행되도록 지정합니다. 격리 수준에 대한 자세한 내용은 SET TRANSACTION ISOLATION LEVEL참조하세요.
ROWLOCK
페이지 또는 테이블 잠금이 일반적으로 사용될 때 행 잠금을 사용하도록 지정합니다.
SNAPSHOT
격리 수준에서 작동하는 트랜잭션에 지정하는 경우 ROWLOCK
및 UPDLOCK
과 같은 잠금이 필요한 다른 테이블 힌트와 함께 HOLDLOCK
을 사용하지 않으면 행 잠금이 수행되지 않습니다.
ROWLOCK
은 클러스터형 columnstore 인덱스가 있는 테이블에 사용할 수 없습니다. 다음 예제는 애플리케이션에 오류 651을 반환합니다.
UPDATE [dbo].[FactResellerSalesXL_CCI] WITH (ROWLOCK)
SET UnitPrice = 50
WHERE ProductKey = 150;
직렬화 가능
HOLDLOCK
과 동일합니다. 필요한 테이블 또는 데이터 페이지가 더 이상 필요 없을 때 트랜잭션의 완료 여부와 관계없이 즉시 공유 잠금을 해제하지 않고 트랜잭션 완료 시까지 유지함으로써 공유 잠금을 더욱 제한적으로 만듭니다.
SERIALIZABLE
격리 수준에서 실행되는 트랜잭션과 동일한 잠금 기능으로 검색이 수행됩니다. 격리 수준에 대한 자세한 내용은 SET TRANSACTION ISOLATION LEVEL참조하세요.
SNAPSHOT
적용 대상: SQL Server 2014(12.x) 이상
메모리 최적화 테이블은 SNAPSHOT
격리로 액세스됩니다.
SNAPSHOT
은 다음 예제와 같이 메모리 최적화 테이블에서만 사용할 수 있습니다(디스크 기반 테이블에서 사용할 수 없음). 자세한 내용은 메모리 액세스에 최적화된 테이블 소개를 참조하세요.
SELECT *
FROM dbo.Customers AS c WITH (SNAPSHOT)
LEFT OUTER JOIN dbo.[Order History] AS oh
ON c.customer_id = oh.customer_id;
SPATIAL_WINDOW_MAX_CELLS = <integer_value>
적용 대상: SQL Server 2012(11.x) 이상 버전
geometry 또는 geography 개체의 공간 분할(tessellation)에 사용할 최대 셀 개수를 지정합니다. <integer_value>는 1에서 8192 사이의 값입니다.
이 옵션을 사용하면 기본 및 보조 필터 실행 시간을 서로 조정하여 쿼리 실행 시간을 미세 조정할 수 있습니다. 숫자가 클수록 보조 필터 실행 시간은 줄어들고 기본 실행 필터 시간은 늘어나며 숫자가 작을수록 기본 필터 실행 시간은 줄어들고 보조 필터 실행은 늘어납니다. 밀도가 높은 공간 데이터의 경우 숫자가 높을수록 기본 필터로 더 정확한 근사값을 제공하여 실행 시간이 빨라지고 보조 필터 실행 시간이 줄어듭니다. 스파스 데이터가 많을수록 기본 필터 실행 시간이 줄어듭니다.
수동 및 자동 표 공간 분할에 모두 이 옵션을 사용할 수 있습니다.
TABLOCK
획득한 잠금이 테이블 수준에 적용되도록 지정합니다. 획득한 잠금 유형은 실행 중인 문에 따라 달라집니다. 예를 들어 SELECT
문은 공유 잠금을 획득할 수 있습니다.
TABLOCK
을 지정하여 공유 잠금을 행 또는 페이지 수준 대신 전체 테이블에 적용할 수 있습니다.
HOLDLOCK
도 지정한 경우에는 트랜잭션이 끝날 때까지 테이블 잠금이 유지됩니다.
문을 사용하여 INSERT INTO <target_table> SELECT <columns> FROM <source_table>
데이터를 힙으로 가져올 때 대상 테이블에 대한 힌트를 지정하여 문에 대한 최소 로깅 및 최적 잠금을 TABLOCK
사용하도록 설정할 수 있습니다. 또한 데이터베이스의 복구 모델은 단순 또는 대량으로 지정해야 합니다.
TABLOCK
힌트로 힙 또는 클러스터형 columnstore 인덱스에 대한 병렬 삽입도 가능합니다. 자세한 내용은 insert
OPENROWSET 대량 행 집합 공급자와 함께 TABLOCK
을 사용하여 테이블로 데이터를 가져오는 경우, 여러 클라이언트에서 로깅 및 잠금이 최적화된 상태에서 대상 테이블로 데이터를 동시에 로드할 수 있습니다. 자세한 내용은 대량 가져오기최소 로깅에 대한
TABLOCKX
테이블을 배타적으로 잠그도록 지정합니다.
UPDLOCK
업데이트 잠금을 사용하고 트랜잭션이 완료될 때까지 유지하도록 지정합니다.
UPDLOCK
은 읽기 작업을 위해 행 수준 또는 페이지 수준에서만 업데이트 잠금을 사용합니다. 다른 이유로 테이블 수준 잠금과 UPDLOCK
결합되거나 테이블 수준 잠금을 사용하는 경우 TABLOCK
배타적(X) 잠금이 대신 수행됩니다.
UPDLOCK
을 지정하면 READCOMMITTED
및 READCOMMITTEDLOCK
격리 수준 힌트가 무시됩니다. 예를 들어 세션의 격리 수준이 SERIALIZABLE
로 설정되고 쿼리가 (UPDLOCK
, READCOMMITTED
)를 지정할 경우 READCOMMITTED
힌트는 무시되고 트랜잭션은 SERIALIZABLE
격리 수준을 사용하여 실행됩니다.
XLOCK
배타적 잠금을 사용하고 트랜잭션이 완료될 때까지 유지하도록 지정합니다.
ROWLOCK
, PAGLOCK
또는 TABLOCK
과 함께 지정한 경우에는 배타적 잠금이 적절한 세분성 수준에 적용됩니다.
설명
테이블을 쿼리 계획으로 액세스하지 않는 경우에는 테이블 힌트가 무시됩니다. 이는 최적화 프로그램이 테이블에 전혀 액세스하지 않기로 선택하거나 인덱싱된 뷰에 대신 액세스하기 때문에 발생할 수 있습니다. 후자의 경우 OPTION (EXPAND VIEWS)
쿼리 힌트를 사용하여 인덱싱된 뷰에 액세스하지 못할 수 있습니다.
모든 잠금 힌트는 뷰에서 참조되는 테이블과 뷰를 포함하여 쿼리 계획에서 액세스하는 모든 테이블과 뷰로 전달됩니다. 또한 SQL Server는 해당되는 잠금 일관성 검사를 수행합니다.
행 수준 잠금을 획득하는 ROWLOCK
, UPDLOCK
및 XLOCK
잠금 힌트는 실제 데이터 행이 아닌 인덱스 키에 잠금을 배치할 수 있습니다. 예를 들어 테이블에 비클러스터형 인덱스가 있고 잠금 힌트를 사용하는 SELECT
문이 포함 인덱스에 의해 처리되는 경우 기본 테이블의 데이터 행이 아닌 커버링 인덱스에 있는 인덱스 키에서 잠금이 획득됩니다.
다른 테이블에 있는 열에 액세스하는 식 또는 함수에 의해 계산되는 계산 열이 테이블에 있는 경우 테이블 힌트는 해당 테이블에서 사용되지 않으며 전파되지 않습니다. 예를 들어 NOLOCK
테이블 힌트는 쿼리의 테이블에 지정됩니다. 이 테이블에는 다른 테이블에 있는 열에 액세스하는 식과 함수의 조합에 의해 계산되는 계산 열이 있습니다. 이러한 식과 함수에 의해 참조되는 테이블은 액세스될 때 NOLOCK
테이블 힌트를 사용하지 않습니다.
SQL Server는 FROM
절의 각 테이블에 대해 다음 그룹 각각에서 둘 이상의 테이블 힌트를 허용하지 않습니다.
- 세분성 힌트:
PAGLOCK
,NOLOCK
,READCOMMITTEDLOCK
,ROWLOCK
,TABLOCK
또는TABLOCKX
. - 격리 수준 힌트:
HOLDLOCK
,NOLOCK
,READCOMMITTED
,REPEATABLEREAD
,SERIALIZABLE
.
필터링된 인덱스 힌트
필터링된 인덱스를 테이블 힌트로 사용할 수 있지만 쿼리에서 선택하는 모든 행을 포함하지 않는 경우 쿼리 최적화 프로그램에서 오류 8622를 생성합니다. 다음은 잘못된 필터링된 인덱스 힌트에 대한 예입니다. 이 예제에서는 필터링된 인덱스 FIBillOfMaterialsWithComponentID
만든 다음 SELECT
문의 인덱스 힌트로 사용합니다. 필터링된 인덱스 조건자에는 ComponentID 533, 324 및 753의 데이터 행이 포함됩니다. 쿼리 조건자에도 ComponentID 533, 324 및 753의 데이터 행이 포함되지만 필터링된 인덱스에 없는 ComponentID 855 및 924도 포함하도록 결과 집합이 확장되어 있습니다. 따라서 쿼리 최적화 프로그램에서는 필터링된 인덱스 힌트를 사용할 수 없으며 오류 8622가 발생합니다. 자세한 내용은 필터링된 인덱스 만들기
IF EXISTS (SELECT name FROM sys.indexes
WHERE name = N'FIBillOfMaterialsWithComponentID'
AND object_id = OBJECT_ID(N'Production.BillOfMaterials'))
DROP INDEX FIBillOfMaterialsWithComponentID
ON Production.BillOfMaterials;
GO
CREATE NONCLUSTERED INDEX [FIBillOfMaterialsWithComponentID]
ON Production.BillOfMaterials(ComponentID, StartDate, EndDate)
WHERE ComponentID IN (533, 324, 753);
GO
SELECT StartDate, ComponentID
FROM Production.BillOfMaterials
WITH (INDEX (FIBillOfMaterialsWithComponentID))
WHERE ComponentID IN (533, 324, 753, 855, 924);
GO
쿼리 최적화 프로그램은 SET
옵션에 필터링된 인덱스에 필요한 값이 없는 경우 인덱스 힌트를 고려하지 않습니다. 자세한 내용은 CREATE INDEX
NOEXPAND 사용
NOEXPAND
는 인덱싱된 뷰에만 적용됩니다. 인덱싱된 뷰란 고유한 클러스터형 인덱스가 만들어져 있는 뷰를 의미합니다. 인덱싱된 뷰와 기본 테이블 모두에 있는 열에 대한 참조가 포함된 쿼리의 경우 쿼리 최적화 프로그램이 쿼리를 실행하는 데 인덱싱된 뷰를 사용하는 것이 최상의 방법이라고 결정하면 뷰의 인덱스를 사용합니다. 이 기능은 인덱싱된 뷰 일치라고 합니다. 서비스 팩 1이 포함된 SQL Server 2016(13.x) 이전에는 특정 버전의 SQL Server에서만 쿼리 최적화 프로그램에서 인덱싱된 뷰를 자동으로 사용할 수 있습니다. 서비스 팩 1 이상 버전의 SQL Server 2016(13.x)에서는 모든 버전이 인덱싱된 뷰의 자동 사용을 지원합니다. Azure SQL 데이터베이스와 Azure SQL Managed Instance도 NOEXPAND
힌트를 지정하지 않고 인덱싱된 뷰를 자동으로 사용하도록 지원합니다.
자세한 내용은 쿼리 처리 아키텍처 가이드를 참조하세요.
Windows의 SQL Server 버전에서 지원되는 기능 목록은 다음을 참조하세요.
- SQL Server 2022의 버전 및 지원하는 기능
- SQL Server 2019의 버전 및 지원되는 기능
- 버전 및 SQL Server 2017 의 지원 되는 기능
- 버전 및 SQL Server 2016 의 지원 되는 기능
그러나 쿼리 최적화 프로그램에서 일치를 위해 인덱싱된 뷰를 고려하거나 NOEXPAND
힌트로 참조되는 인덱싱된 뷰를 사용하려면 다음 SET
옵션을 ON
설정해야 합니다.
- ANSI_NULLS
- ANSI_PADDING
- ANSI_WARNINGS
- ARITHABORT 1
- CONCAT_NULL_YIELDS_NULL
- QUOTED_IDENTIFIER
ANSI_WARNINGS
ON
설정되면 1ARITHABORT
암시적으로 ON
설정됩니다. 따라서 이 설정을 수동으로 조정할 필요가 없습니다.
또한 NUMERIC_ROUNDABORT
옵션은 OFF
설정해야 합니다.
쿼리 최적화 프로그램이 인덱싱된 뷰에 대한 인덱스를 강제로 사용하게 하려면 NOEXPAND
옵션을 지정합니다. 이 힌트는 뷰가 쿼리에서도 명명되어 있는 경우에만 사용할 수 있습니다. SQL Server는 FROM
절에서 뷰의 이름을 직접 지정하지 않는 쿼리에서 인덱싱된 특정 뷰를 사용하도록 강제하는 힌트를 제공하지 않습니다. 그러나 쿼리 최적화 프로그램은 쿼리에서 직접 참조되지 않더라도 인덱싱된 뷰를 사용하는 것을 고려합니다. SQL Server 데이터베이스 엔진은 NOEXPAND
테이블 힌트를 사용하는 경우에만 인덱싱된 뷰에 대한 통계를 자동으로 만듭니다. 이 힌트를 생략하면 수동으로 통계를 생성하여 확인할 수 없는 누락된 통계에 대한 실행 계획 경고가 발생할 수 있습니다.
쿼리 최적화 중에 데이터베이스 엔진 쿼리가 뷰를 직접 참조하고 힌트가 사용될 때 자동으로 또는 수동으로 생성된 뷰 통계를 NOEXPAND
사용합니다.
쿼리 힌트로 테이블 힌트 사용
테이블 힌트OPTION (TABLE HINT)
절을 사용하여 쿼리 힌트로 지정할 수도 있습니다. 테이블 힌트는 계획 지침의 컨텍스트에서 쿼리 힌트로만 사용하는 것이 좋습니다. 임시 쿼리의 경우 이러한 힌트를 테이블 힌트로만 지정합니다. 자세한 내용은
사용 권한
KEEPIDENTITY
, IGNORE_CONSTRAINTS
및 IGNORE_TRIGGERS
힌트에는 테이블에 대한 ALTER
권한이 필요합니다.
예제
A. TABLOCK 힌트를 사용하여 잠금 방법 지정
다음 예제에서는 AdventureWorks2022 데이터베이스의 Production.Product
테이블에서 공유 잠금이 수행되고 UPDATE
문이 끝날 때까지 유지되도록 지정합니다.
UPDATE Production.Product WITH (TABLOCK)
SET ListPrice = ListPrice * 1.10
WHERE ProductNumber LIKE 'BK-%';
GO
B. FORCESEEK 힌트를 사용하여 인덱스 찾기 작업 지정
다음 예제에서는 인덱스를 지정하지 않고 힌트를 사용하여 FORCESEEK
쿼리 최적화 프로그램이 AdventureWorks2022 데이터베이스의 테이블에서 인덱스 검색 작업을 Sales.SalesOrderDetail
수행하도록 합니다.
SELECT *
FROM Sales.SalesOrderHeader AS h
INNER JOIN Sales.SalesOrderDetail AS d WITH (FORCESEEK)
ON h.SalesOrderID = d.SalesOrderID
WHERE h.TotalDue > 100
AND (d.OrderQty > 5
OR d.LineTotal < 1000.00);
GO
다음 예제에서는 인덱스와 함께 FORCESEEK
힌트를 사용하여 쿼리 최적화 프로그램이 지정된 인덱스 및 인덱스 열에서 인덱스 찾기 작업을 수행하도록 지정합니다.
SELECT h.SalesOrderID,
h.TotalDue,
d.OrderQty
FROM Sales.SalesOrderHeader AS h
INNER JOIN Sales.SalesOrderDetail AS d
WITH (FORCESEEK (PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID (SalesOrderID)))
ON h.SalesOrderID = d.SalesOrderID
WHERE h.TotalDue > 100
AND (d.OrderQty > 5
OR d.LineTotal < 1000.00);
GO
C. FORCESCAN 힌트를 사용하여 인덱스 검색 작업 지정
다음 예제에서는 힌트를 사용하여 FORCESCAN
쿼리 최적화 프로그램이 AdventureWorks2022 데이터베이스의 Sales.SalesOrderDetail
테이블에서 검사 작업을 수행하도록 강제합니다.
SELECT h.SalesOrderID,
h.TotalDue,
d.OrderQty
FROM Sales.SalesOrderHeader AS h
INNER JOIN Sales.SalesOrderDetail AS d WITH (FORCESCAN)
ON h.SalesOrderID = d.SalesOrderID
WHERE h.TotalDue > 100
AND (d.OrderQty > 5
OR d.LineTotal < 1000.00);