Loading...
MySQL 9.5 Reference Manual 9.5의 10.9.3 Optimizer Hints의 한국어 번역본입니다.
아래의 경우에 피드백에서 신고해주신다면 반영하겠습니다.
감사합니다 :)
optimizer 전략을 제어하는 한 가지 방법은
optimizer_switch 시스템
변수를 설정하는 것입니다( Section 10.9.2, “Switchable Optimizations” 참조).
이 변수의 변경은 이후에 실행되는 모든
쿼리의 실행에 영향을 줍니다.
하나의 쿼리를 다른 쿼리와
다르게 동작하게 하려면 각 쿼리를 실행하기 전에
optimizer_switch를 변경해야 합니다.
optimizer를 제어하는 또 다른 방법은 optimizer
힌트를 사용하는 것으로, 이는 개별 문장 내에
지정할 수 있습니다.
optimizer 힌트는 문장 단위로 적용되므로,
optimizer_switch를 사용하는 것보다 문장 실행 계획을 더 세밀하게
제어할 수 있습니다.
예를 들어,
하나의 문장 내에서 어떤 테이블에는 최적화를 활성화하고
다른 테이블에는 해당 최적화를 비활성화할 수 있습니다.
문장 내부의 힌트는
optimizer_switch 플래그보다 우선합니다.
예:
1SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY, f2_idx) */ f1 2 FROM t3 WHERE f1 > 30 AND f1 < 33; 3SELECT /*+ BKA(t1) NO_BKA(t2) */ * FROM t1 INNER JOIN t2 WHERE ...; 4SELECT /*+ NO_ICP(t1, t2) */ * FROM t1 INNER JOIN t2 WHERE ...; 5SELECT /*+ SEMIJOIN(FIRSTMATCH, LOOSESCAN) */ * FROM t1 ...; 6EXPLAIN SELECT /*+ NO_ICP(t1) */ * FROM t1 WHERE ...; 7SELECT /*+ MERGE(dt) */ * FROM (SELECT * FROM t1) AS dt; 8INSERT /*+ SET_VAR(foreign_key_checks=OFF) */ INTO t2 VALUES(2);
여기에서 설명하는 optimizer 힌트는 Section 10.9.4, “Index Hints”에 설명된 인덱스 힌트와는 다릅니다. optimizer 힌트와 인덱스 힌트는 각각 또는 함께 사용할 수 있습니다.
Optimizer 힌트는 서로 다른 범위(scope) 수준에 적용됩니다:
Global: 힌트가 전체 문장에 영향을 줍니다.
Query block: 힌트가 문장 내 특정 쿼리 블록에 영향을 줍니다.
Table-level: 힌트가 쿼리 블록 내 특정 테이블에 영향을 줍니다.
Index-level: 힌트가 테이블 내 특정 인덱스에 영향을 줍니다.
다음 표는 사용 가능한 optimizer 힌트, 이들이 영향을 미치는 optimizer 전략, 그리고 적용 가능한 범위를 요약한 것입니다. 자세한 내용은 이후에 제공됩니다.
Table 10.2 Optimizer Hints Available
| Hint Name | Description | Applicable Scopes |
|---|---|---|
BKA,<br> NO_BKA | Batched Key Access 조인 처리에 영향을 줍니다. | Query block, table |
BNL,<br> NO_BNL | 해시 조인 최적화에 영향을 줍니다. | Query block, table |
DERIVED_CONDITION_PUSHDOWN,<br> NO_DERIVED_CONDITION_PUSHDOWN | 구체화된 파생 테이블에 대해 파생 조건 푸시다운 최적화를 사용하거나 무시합니다. | Query block, table |
GROUP_INDEX,<br> NO_GROUP_INDEX | GROUP BY 연산에서 인덱스 스캔을 위해 지정된 인덱스(들)를 사용하거나 무시합니다. | Index |
HASH_JOIN,<br> NO_HASH_JOIN | 해시 조인 최적화에 영향을 줍니다(MySQL 9.5에서는 효과 없음). | Query block, table |
INDEX,<br> NO_INDEX | JOIN_INDEX,<br> GROUP_INDEX,<br> ORDER_INDEX의 조합으로 작동하거나,<br> NO_JOIN_INDEX,<br> NO_GROUP_INDEX,<br> NO_ORDER_INDEX의 조합으로 작동합니다. | Index |
INDEX_MERGE,<br> NO_INDEX_MERGE | 인덱스 머지 최적화에 영향을 줍니다. | Table, index |
JOIN_FIXED_ORDER | 조인 순서를 위해 FROM 절에 지정된 테이블 순서를 사용합니다. | Query block |
JOIN_INDEX,<br> NO_JOIN_INDEX | 임의의 접근 방식에 대해 지정된 인덱스(들)를 사용하거나 무시합니다. | Index |
JOIN_ORDER | 조인 순서를 위해 힌트에 지정된 테이블 순서를 사용합니다. | Query block |
JOIN_PREFIX | 조인 실행 계획의 처음 부분에 대해 힌트에 지정된 테이블 순서를 사용합니다. | Query block |
JOIN_SUFFIX | 조인 실행 계획의 마지막 부분에 대해 힌트에 지정된 테이블 순서를 사용합니다. | Query block |
MAX_EXECUTION_TIME | 문장 실행 시간을 제한합니다. | Global |
MERGE,<br> NO_MERGE | 파생 테이블/뷰를 outer 쿼리 블록으로 merge할지 여부에 영향을 줍니다. | Table |
MRR,<br> NO_MRR | Multi-Range Read 최적화에 영향을 줍니다. | Table, index |
NO_ICP | 인덱스 조건 푸시다운 최적화에 영향을 줍니다. | Table, index |
NO_RANGE_OPTIMIZATION | range 최적화에 영향을 줍니다. | Table, index |
ORDER_INDEX,<br> NO_ORDER_INDEX | 행 정렬을 위해 지정된 인덱스(들)를 사용하거나 무시합니다. | Index |
QB_NAME | 쿼리 블록에 이름을 할당합니다. | Query block |
RESOURCE_GROUP | 문장 실행 동안 리소스 그룹을 설정합니다. | Global |
SEMIJOIN,<br> NO_SEMIJOIN | 세미조인 및 안티조인 전략에 영향을 줍니다. | Query block |
SKIP_SCAN,<br> NO_SKIP_SCAN | Skip Scan 최적화에 영향을 줍니다. | Table, index |
SET_VAR | 문장 실행 동안 변수를 설정합니다. | Global |
SUBQUERY | 구체화 및<br> IN-to-EXISTS<br> 서브쿼리 전략에 영향을 줍니다. | Query block |
| Hint Name | Description | Applicable Scopes |
|---|
최적화를 비활성화하면 optimizer가 해당 전략을 사용하지 못하게 됩니다. 최적화를 활성화한다는 것은 optimizer가 문장 실행에 적용 가능한 경우 그 전략을 자유롭게 사용할 수 있음을 의미할 뿐이며, optimizer가 반드시 그것을 사용한다는 뜻은 아닙니다.
MySQL은 Section 11.7, “Comments”에 설명된 대로
SQL 문장에서 주석을 지원합니다.
optimizer 힌트는 /*+ ... */ 주석 안에서 지정해야 합니다.
즉, optimizer 힌트는 /* ... */
C 스타일 주석 구문의 변형을 사용하며,
/* 주석 시작 시퀀스 뒤에
+ 문자를 둡니다.
예:
1/*+ BKA(t1) */ 2/*+ BNL(t1, t2) */ 3/*+ NO_RANGE_OPTIMIZATION(t4 PRIMARY) */ 4/*+ QB_NAME(qb2) */
+ 문자 뒤에는 공백을 둘 수 있습니다.
파서는 다음의 초기 키워드 뒤에서 optimizer 힌트 주석을
인식합니다:
SELECT,
UPDATE,
INSERT,
REPLACE,
DELETE 문장.
힌트는 다음 컨텍스트에서 허용됩니다:
1SELECT /*+ ... */ ... 2INSERT /*+ ... */ ... 3REPLACE /*+ ... */ ... 4UPDATE /*+ ... */ ... 5DELETE /*+ ... */ ...
1(SELECT /*+ ... */ ... ) 2(SELECT ... ) UNION (SELECT /*+ ... */ ... ) 3(SELECT /*+ ... */ ... ) UNION (SELECT /*+ ... */ ... ) 4UPDATE ... WHERE x IN (SELECT /*+ ... */ ...) 5INSERT ... SELECT /*+ ... */ ...
EXPLAIN이 붙은 힌트 사용 가능 문장.
예:1EXPLAIN SELECT /*+ ... */ ... 2EXPLAIN UPDATE ... WHERE x IN (SELECT /*+ ... */ ...)
이는 optimizer 힌트가 실행 계획에 어떤 영향을 미치는지
확인하기 위해
EXPLAIN을 사용할 수 있음을 의미합니다.
EXPLAIN 직후에
SHOW WARNINGS를 사용하여
힌트가 어떻게 사용되었는지 확인하십시오.
이어지는 SHOW WARNINGS에 의해 표시되는 확장된 EXPLAIN
출력은 어떤 힌트가 사용되었는지 나타냅니다.
무시된 힌트는 표시되지 않습니다.
하나의 힌트 주석에는 여러 개의 힌트가 포함될 수 있지만, 하나의 쿼리 블록에는 여러 개의 힌트 주석을 포함할 수 없습니다. 다음은 유효한 예입니다:
1SELECT /*+ BNL(t1) BKA(t2) */ ...
그러나 다음은 유효하지 않습니다:
1SELECT /*+ BNL(t1) */ /* BKA(t2) */ ...
하나의 힌트 주석에 여러 힌트가 포함된 경우, 중복 및 충돌이 발생할 수 있습니다. 다음 일반적인 지침이 적용됩니다. 특정 힌트 유형에 대해서는 힌트 설명에서 추가 규칙이 제시될 수 있습니다.
중복 힌트:
/*+ MRR(idx1) MRR(idx1) */와 같은 힌트의 경우,
MySQL은 첫 번째 힌트를 사용하고
중복 힌트에 대한 경고를 발생시킵니다.
충돌하는 힌트:
/*+ MRR(idx1) NO_MRR(idx1) */와 같은 힌트의 경우,
MySQL은 첫 번째 힌트를 사용하고
두 번째 충돌 힌트에 대한 경고를 발생시킵니다.
쿼리 블록 이름은 식별자이며, 유효한 이름과 인용 방식에 대한 일반적인 규칙을 따릅니다 ( Section 11.2, “Schema Object Names” 참조).
힌트 이름, 쿼리 블록 이름, 전략 이름은 대소문자를 구분하지 않습니다. 테이블 및 인덱스 이름에 대한 참조는 Section 11.2.3, “Identifier Case Sensitivity”에 설명된 식별자 대소문자 구분 규칙을 따릅니다.
Join-order 힌트는 optimizer가 테이블을 조인하는 순서에 영향을 줍니다.
JOIN_FIXED_ORDER 힌트의 구문:
1hint_name([@query_block_name])
기타 join-order 힌트의 구문:
1hint_name([@query_block_name] tbl_name [, tbl_name] ...) 2hint_name(tbl_name[@query_block_name] [, tbl_name[@query_block_name]] ...)
구문은 다음 용어를 참조합니다:
hint_name: 다음 힌트 이름이
허용됩니다:
JOIN_FIXED_ORDER:
optimizer가 FROM
절에 나타나는 순서대로 테이블을 조인하도록 강제합니다.
이는 SELECT STRAIGHT_JOIN을 지정하는 것과 동일합니다.
JOIN_ORDER:
optimizer가 지정된 테이블 순서를 사용하여 테이블을 조인하도록 지시합니다.
힌트는 이름이 지정된 테이블에 적용됩니다.
optimizer는 이름이 지정되지 않은 테이블을
지정된 테이블 사이를 포함한 어디든 배치할 수 있습니다.
JOIN_PREFIX:
optimizer가 조인 실행 계획의 처음 테이블들에 대해
지정된 테이블 순서를 사용하도록 지시합니다.
힌트는 이름이 지정된 테이블에 적용됩니다.
optimizer는 나머지 테이블을 모두
이름이 지정된 테이블 뒤에 배치합니다.
JOIN_SUFFIX:
optimizer가 조인 실행 계획의 마지막 테이블들에 대해
지정된 테이블 순서를 사용하도록 지시합니다.
힌트는 이름이 지정된 테이블에 적용됩니다.
optimizer는 다른 모든 테이블을
이름이 지정된 테이블 앞에 배치합니다.
tbl_name: 문장에서 사용되는
테이블 이름입니다.
테이블 이름이 지정된 힌트는 그 이름이 지정된 모든 테이블에
적용됩니다.
JOIN_FIXED_ORDER 힌트는
테이블 이름을 지정하지 않으며,
해당 힌트가 포함된 쿼리 블록의
FROM 절에 있는 모든 테이블에 적용됩니다.
테이블에 별칭이 있는 경우, 힌트는 테이블 이름이 아니라 별칭을 참조해야 합니다.
힌트에서 테이블 이름은 스키마 이름과 함께 한정할 수 없습니다.
query_block_name: 힌트가 적용되는
쿼리 블록입니다.
힌트에 선행
@query_block_name이 없으면,
힌트는 그것이 포함된 쿼리 블록에 적용됩니다.
tbl_name@query_block_name
구문에서는 힌트가 지정된 쿼리 블록의
지정된 테이블에 적용됩니다.
쿼리 블록에 이름을 할당하는 방법은
Optimizer Hints for Naming Query Blocks를 참조하십시오.예:
1SELECT 2/*+ JOIN_PREFIX(t2, t5@subq2, t4@subq1) 3 JOIN_ORDER(t4@subq1, t3) 4 JOIN_SUFFIX(t1) */ 5COUNT(*) FROM t1 JOIN t2 JOIN t3 6 WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4) 7 AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
힌트는 outer 쿼리 블록으로 merge된 세미조인 테이블의
동작을 제어합니다.
서브쿼리 subq1과 subq2가
세미조인으로 변환되면,
테이블 t4@subq1과
t5@subq2는 outer 쿼리
블록으로 merge됩니다.
이 경우 outer 쿼리 블록에 지정된 힌트가
t4@subq1,
t5@subq2 테이블의 동작을 제어합니다.
optimizer는 join-order 힌트를 다음 원칙에 따라 해석합니다:
여러 힌트 인스턴스
하나의 JOIN_PREFIX와
하나의 JOIN_SUFFIX만
각각 적용됩니다.
동일 유형의 이후 힌트는
경고와 함께 무시됩니다.
JOIN_ORDER는
여러 번 지정할 수 있습니다.
예:
1/*+ JOIN_PREFIX(t1) JOIN_PREFIX(t2) */
두 번째 JOIN_PREFIX
힌트는 경고와 함께 무시됩니다.
1/*+ JOIN_PREFIX(t1) JOIN_SUFFIX(t2) */
두 힌트 모두 적용 가능합니다. 경고는 발생하지 않습니다.
1/*+ JOIN_ORDER(t1, t2) JOIN_ORDER(t2, t3) */
두 힌트 모두 적용 가능합니다. 경고는 발생하지 않습니다.
충돌하는 힌트
일부 경우, 다음과 같이
JOIN_ORDER와
JOIN_PREFIX가
동시에 만족시킬 수 없는 테이블 순서를 갖도록 지정될 수 있습니다:
1SELECT /*+ JOIN_ORDER(t1, t2) JOIN_PREFIX(t2, t1) */ ... FROM t1, t2;
이 경우, 먼저 지정된 힌트가 적용되며 이후의 충돌 힌트는 경고 없이 무시됩니다. 적용이 불가능한 유효한 힌트는 경고 없이 조용히 무시됩니다.
무시된 힌트
힌트에 지정된 테이블에 순환 종속성이 있으면 힌트는 무시됩니다.
예:
1/*+ JOIN_ORDER(t1, t2) JOIN_PREFIX(t2, t1) */
JOIN_ORDER 힌트는
테이블 t2를
t1에 종속되게 설정합니다.
JOIN_PREFIX 힌트는
테이블 t1이
t2에 종속될 수 없기 때문에
무시됩니다.
무시된 힌트는 확장된
EXPLAIN 출력에 표시되지 않습니다.
const
테이블과의 상호 작용
MySQL optimizer는 조인 순서에서
const 테이블을 항상 먼저 배치하며,
const 테이블의 위치는 힌트로
변경할 수 없습니다.
join-order 힌트에서 const 테이블에 대한 참조는
무시되지만, 힌트 자체는 여전히 적용 가능합니다.
예를 들어, 다음 두 구문은 동일합니다:
1JOIN_ORDER(t1, const_tbl, t2) 2JOIN_ORDER(t1, t2)
확장된
EXPLAIN 출력에 표시되는
수용된 힌트에는 지정된 그대로
const 테이블이 포함됩니다.
조인 연산 유형과의 상호 작용
MySQL은 다음과 같은 여러 조인 유형을 지원합니다:
LEFT, RIGHT,
INNER, CROSS,
STRAIGHT_JOIN.
조인 유형과 충돌하는 힌트는
경고 없이 무시됩니다.
예:
1SELECT /*+ JOIN_PREFIX(t1, t2) */FROM t2 LEFT JOIN t1;
여기서는 힌트에서 요청한 조인 순서와
LEFT JOIN에서 요구하는 순서 간에
충돌이 발생합니다.
힌트는 경고 없이 무시됩니다.
Table-level 힌트는 다음에 영향을 줍니다:
Block Nested-Loop (BNL) 및 Batched Key Access (BKA) 조인 처리 알고리즘의 사용 ( Section 10.2.1.12, “Block Nested-Loop and Batched Key Access Joins” 참조).
파생 테이블, 뷰 참조 또는 공통 테이블 식(Common Table Expression, CTE)을 outer 쿼리 블록으로 merge할지, 내부 임시 테이블을 사용해 구체화할지 여부.
파생 테이블 조건 푸시다운 최적화의 사용 여부. 자세한 내용은 Section 10.2.2.5, “Derived Condition Pushdown Optimization”을 참조하십시오.
이러한 힌트 유형은 특정 테이블 또는 쿼리 블록 내의 모든 테이블에 적용됩니다.
table-level 힌트의 구문:
1hint_name([@query_block_name] [tbl_name [, tbl_name] ...]) 2hint_name([tbl_name@query_block_name [, tbl_name@query_block_name] ...])
구문은 다음 용어를 참조합니다:
hint_name: 다음 힌트 이름이
허용됩니다:
BKA,
NO_BKA: 지정된 테이블에 대해
batched key access를 활성화 또는 비활성화합니다.
DERIVED_CONDITION_PUSHDOWN,
NO_DERIVED_CONDITION_PUSHDOWN:
지정된 테이블에 대해 파생 테이블 조건 푸시다운을
사용할지 여부를 제어합니다.
자세한 내용은
Section 10.2.2.5, “Derived Condition Pushdown Optimization”을
참조하십시오.
HASH_JOIN,
NO_HASH_JOIN:
이 힌트는 MySQL 9.5에서는 아무 효과가 없습니다.
대신 BNL 또는
NO_BNL을 사용하십시오.
MERGE,
NO_MERGE:
지정된 테이블, 뷰 참조 또는
공통 테이블 식에 대해 merging을 활성화하거나,
merging을 비활성화하고 대신 구체화를 사용합니다.
참고
outer 조인의 inner 테이블에 대해 block nested loop 또는 batched key access 힌트를 사용하여 조인 버퍼링을 활성화하려면, outer 조인의 모든 inner 테이블에 대해 조인 버퍼링이 활성화되어야 합니다.
tbl_name: 문장에서 사용되는
테이블 이름입니다.
힌트는 이름이 지정된 모든 테이블에 적용됩니다.
힌트에 테이블 이름이 명시되지 않으면,
해당 힌트는 그것이 포함된 쿼리 블록의 모든 테이블에
적용됩니다.테이블에 별칭이 있는 경우, 힌트는 테이블 이름이 아니라 별칭을 참조해야 합니다.
힌트에서 테이블 이름은 스키마 이름과 함께 한정할 수 없습니다.
query_block_name: 힌트가 적용되는
쿼리 블록입니다.
힌트에 선행
@query_block_name이 없으면,
힌트는 그것이 포함된 쿼리 블록에 적용됩니다.
tbl_name@query_block_name
구문에서는 힌트가 지정된 쿼리 블록의
지정된 테이블에 적용됩니다.
쿼리 블록에 이름을 할당하는 방법은
Optimizer Hints for Naming Query Blocks를 참조하십시오.예:
1SELECT /*+ NO_BKA(t1, t2) */ t1.* FROM t1 INNER JOIN t2 INNER JOIN t3; 2SELECT /*+ NO_BNL() BKA(t1) */ t1.* FROM t1 INNER JOIN t2 INNER JOIN t3; 3SELECT /*+ NO_MERGE(dt) */ * FROM (SELECT * FROM t1) AS dt;
Table-level 힌트는 레코드를 이전 테이블에서 받는 테이블에 적용되며, sender 테이블에는 적용되지 않습니다. 다음 문장을 살펴보십시오:
1SELECT /*+ BNL(t2) */ FROM t1, t2;
optimizer가 먼저 t1을 처리하기로 선택하면,
t2를 읽기 시작하기 전에
t1의 행을 버퍼하여
t2에 Block Nested-Loop 조인을 적용합니다.
optimizer가 대신 t2를 먼저 처리하기로 선택하면,
t2는 sender 테이블이므로
힌트는 아무 효과가 없습니다.
MERGE 및
NO_MERGE 힌트에 대해서는
다음 우선순위 규칙이 적용됩니다:
힌트는 기술적 제약이 아닌 optimizer 휴리스틱보다 우선합니다. (힌트를 제안 형태로 제공해도 효과가 없다면, optimizer가 그것을 무시할 이유가 있는 것입니다.)
힌트는
optimizer_switch 시스템
변수의
derived_merge 플래그보다
우선합니다.
뷰 참조의 경우,
뷰 정의 내의
ALGORITHM={MERGE|TEMPTABLE} 절이
뷰를 참조하는 쿼리에 지정된 힌트보다
우선합니다.
Index-level 힌트는 특정 테이블 또는 인덱스에 대해 optimizer가 사용하는 인덱스 처리 전략에 영향을 줍니다. 이러한 힌트 유형은 인덱스 조건 푸시다운(ICP), Multi-Range Read(MRR), 인덱스 머지 및 range 최적화 사용에 영향을 줍니다 ( Section 10.2.1, “Optimizing SELECT Statements” 참조).
Index-level 힌트의 구문:
1hint_name([@query_block_name] tbl_name [index_name [, index_name] ...]) 2hint_name(tbl_name@query_block_name [index_name [, index_name] ...])
구문은 다음 용어를 참조합니다:
hint_name: 다음 힌트 이름이
허용됩니다:
GROUP_INDEX,
NO_GROUP_INDEX:
GROUP BY 연산에서의 인덱스 스캔을 위해
지정된 인덱스(들)를 사용하거나 무시합니다.
이는 인덱스 힌트
FORCE INDEX FOR GROUP BY,
IGNORE INDEX FOR GROUP BY와
동일합니다.
INDEX,
NO_INDEX:
JOIN_INDEX,
GROUP_INDEX,
ORDER_INDEX의 조합으로 작동하여
서버가 지정된 인덱스(들)를 모든 범위에서
사용하도록 강제하거나,
NO_JOIN_INDEX,
NO_GROUP_INDEX,
NO_ORDER_INDEX의 조합으로 작동하여
서버가 지정된 인덱스(들)를 모든 범위에서
무시하게 합니다.
이는 FORCE INDEX, IGNORE INDEX와
동일합니다.
INDEX_MERGE,
NO_INDEX_MERGE:
지정된 테이블 또는 인덱스에 대해
인덱스 머지 접근 방식을 활성화 또는 비활성화합니다.
이 접근 방식에 대한 정보는
Section 10.2.1.3, “Index Merge Optimization”을
참조하십시오.
이 힌트는 세 가지 인덱스 머지 알고리즘 모두에 적용됩니다.
INDEX_MERGE 힌트는
지정된 테이블에 대해 지정된 인덱스 집합을 사용하여
optimizer가 인덱스 머지를 사용하도록 강제합니다.
인덱스가 지정되지 않으면,
optimizer는 가능한 모든 인덱스 조합을 고려하고
비용이 가장 낮은 조합을 선택합니다.
인덱스 조합이 해당 문장에 적용 불가능한 경우,
힌트는 무시될 수 있습니다.
NO_INDEX_MERGE
힌트는 지정된 인덱스 중 어느 하나라도 포함하는
인덱스 머지 조합을 비활성화합니다.
힌트에 인덱스가 지정되지 않으면,
해당 테이블에 대해 인덱스 머지가 허용되지 않습니다.
JOIN_INDEX,
NO_JOIN_INDEX:
ref, range,
index_merge 등
임의의 접근 방식에 대해 지정된 인덱스(들)를
사용 또는 무시하도록 MySQL을 강제합니다.
이는 FORCE INDEX FOR JOIN,
IGNORE INDEX FOR JOIN과
동일합니다.
MRR,
NO_MRR:
지정된 테이블 또는 인덱스에 대해 MRR을 활성화 또는 비활성화합니다.
MRR 힌트는 InnoDB 및
MyISAM 테이블에만 적용됩니다.
이 접근 방식에 대한 정보는
Section 10.2.1.11, “Multi-Range Read Optimization”을
참조하십시오.
NO_ICP:
지정된 테이블 또는 인덱스에 대해 ICP를 비활성화합니다.
기본적으로 ICP는 후보 최적화 전략이므로,
이를 활성화하는 힌트는 제공되지 않습니다.
이 접근 방식에 대한 정보는
Section 10.2.1.6, “Index Condition Pushdown Optimization”을
참조하십시오.
NO_RANGE_OPTIMIZATION:
지정된 테이블 또는 인덱스에 대해
인덱스 range 접근을 비활성화합니다.
이 힌트는 또한 해당 테이블 또는 인덱스에 대해
인덱스 머지와 느슨한 인덱스 스캔을 비활성화합니다.
기본적으로 range 접근은 후보 최적화 전략이므로,
이를 활성화하는 힌트는 제공되지 않습니다.
이 힌트는 range 수가 많고 range 최적화가 많은 자원을 요구하는 경우에 유용할 수 있습니다.
ORDER_INDEX,
NO_ORDER_INDEX:
행 정렬을 위해 MySQL이 지정된 인덱스(들)를
사용하거나 무시하게 합니다.
이는 FORCE INDEX FOR ORDER BY,
IGNORE INDEX FOR ORDER BY와
동일합니다.
SKIP_SCAN,
NO_SKIP_SCAN:
지정된 테이블 또는 인덱스에 대해
Skip Scan 접근 방식을 활성화 또는 비활성화합니다.
이 접근 방식에 대한 정보는
Skip Scan Range Access Method를
참조하십시오.
SKIP_SCAN 힌트는
지정된 테이블에 대해 지정된 인덱스 집합을 사용하여
optimizer가 Skip Scan을 사용하도록 강제합니다.
인덱스가 지정되지 않으면,
optimizer는 가능한 모든 인덱스를 고려하고
비용이 가장 낮은 인덱스를 선택합니다.
인덱스가 해당 문장에 적용 불가능한 경우,
힌트는 무시될 수 있습니다.
NO_SKIP_SCAN
힌트는 지정된 인덱스에 대해 Skip Scan을 비활성화합니다.
힌트에 인덱스가 지정되지 않으면,
해당 테이블에 대해 Skip Scan이 허용되지 않습니다.
tbl_name: 힌트가 적용되는
테이블입니다.
index_name: 지정된 테이블에 있는
인덱스의 이름입니다.
힌트는 이름이 지정된 모든 인덱스에 적용됩니다.
힌트에 인덱스가 지정되지 않으면,
해당 테이블의 모든 인덱스에 적용됩니다.
Primary key를 참조하려면
PRIMARY라는 이름을 사용하십시오.
테이블의 인덱스 이름을 확인하려면
SHOW INDEX를 사용하십시오.
query_block_name: 힌트가 적용되는
쿼리 블록입니다.
힌트에 선행
@query_block_name이 없으면,
힌트는 그것이 포함된 쿼리 블록에 적용됩니다.
tbl_name@query_block_name
구문에서는 힌트가 지정된 쿼리 블록의
지정된 테이블에 적용됩니다.
쿼리 블록에 이름을 할당하는 방법은
Optimizer Hints for Naming Query Blocks를 참조하십시오.예:
1SELECT /*+ INDEX_MERGE(t1 f3, PRIMARY) */ f2 FROM t1 2 WHERE f1 = 'o' AND f2 = f3 AND f3 <= 4; 3SELECT /*+ MRR(t1) */ * FROM t1 WHERE f2 <= 3 AND 3 <= f3; 4SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY, f2_idx) */ f1 5 FROM t3 WHERE f1 > 30 AND f1 < 33; 6INSERT INTO t3(f1, f2, f3) 7 (SELECT /*+ NO_ICP(t2) */ t2.f1, t2.f2, t2.f3 FROM t1,t2 8 WHERE t1.f1=t2.f1 AND t2.f2 BETWEEN t1.f1 9 AND t1.f2 AND t2.f2 + 1 >= t1.f1 + 1); 10SELECT /*+ SKIP_SCAN(t1 PRIMARY) */ f1, f2 11 FROM t1 WHERE f2 > 40;
다음 예에서는 인덱스 머지 힌트를 사용하지만,
다른 index-level 힌트도 힌트 무시와
optimizer 힌트와
optimizer_switch 시스템
변수 또는 인덱스 힌트 간의
우선순위에 대해 동일한 원칙을 따릅니다.
테이블 t1에 컬럼
a, b,
c, d가 있고,
a, b, c에 대해 각각
i_a, i_b,
i_c라는 이름의 인덱스가 존재한다고 가정합니다:
1SELECT /*+ INDEX_MERGE(t1 i_a, i_b, i_c)*/ * FROM t1 2 WHERE a = 1 AND b = 2 AND c = 3 AND d = 4;
이 경우 (i_a, i_b, i_c)에 대해
인덱스 머지가 사용됩니다.
1SELECT /*+ INDEX_MERGE(t1 i_a, i_b, i_c)*/ * FROM t1 2 WHERE b = 1 AND c = 2 AND d = 3;
이 경우 (i_b, i_c)에 대해
인덱스 머지가 사용됩니다.
1/*+ INDEX_MERGE(t1 i_a, i_b) NO_INDEX_MERGE(t1 i_b) */
동일 테이블에 대한 이전 힌트가 있기 때문에
NO_INDEX_MERGE는
무시됩니다.
1/*+ NO_INDEX_MERGE(t1 i_a, i_b) INDEX_MERGE(t1 i_b) */
동일 테이블에 대한 이전 힌트가 있기 때문에
INDEX_MERGE는
무시됩니다.
INDEX_MERGE 및
NO_INDEX_MERGE
optimizer 힌트에 대해서는
다음 우선순위 규칙이 적용됩니다:
optimizer 힌트가 지정되어 있고 적용 가능하면,
optimizer_switch 시스템
변수의 인덱스 머지 관련 플래그보다
우선합니다.
1SET optimizer_switch='index_merge_intersection=off'; 2SELECT /*+ INDEX_MERGE(t1 i_b, i_c) */ * FROM t1 3WHERE b = 1 AND c = 2 AND d = 3;
이 경우 힌트가
optimizer_switch보다 우선합니다.
(i_b, i_c)에 대해 인덱스 머지가
사용됩니다.
1SET optimizer_switch='index_merge_intersection=on'; 2SELECT /*+ INDEX_MERGE(t1 i_b) */ * FROM t1 3WHERE b = 1 AND c = 2 AND d = 3;
힌트는 하나의 인덱스만 지정하므로 적용 불가능하며,
optimizer_switch
플래그(on)가 적용됩니다.
optimizer가 비용 효율적이라고 판단하면
인덱스 머지가 사용됩니다.
1SET optimizer_switch='index_merge_intersection=off'; 2SELECT /*+ INDEX_MERGE(t1 i_b) */ * FROM t1 3WHERE b = 1 AND c = 2 AND d = 3;
힌트는 하나의 인덱스만 지정하므로 적용 불가능하며,
optimizer_switch
플래그(off)가 적용됩니다.
인덱스 머지는 사용되지 않습니다.
Index-level optimizer 힌트
GROUP_INDEX, INDEX,
JOIN_INDEX, ORDER_INDEX는
해당하는 FORCE INDEX 힌트보다
항상 우선합니다.
즉, 이들은 FORCE INDEX 힌트가
무시되게 합니다.
마찬가지로
NO_GROUP_INDEX,
NO_INDEX,
NO_JOIN_INDEX,
NO_ORDER_INDEX 힌트는
각각의 IGNORE INDEX
와 동일한 힌트보다 항상 우선하여,
그들을 무시하게 합니다.
Index-level optimizer 힌트
GROUP_INDEX,
NO_GROUP_INDEX,
INDEX,NO_INDEX,
JOIN_INDEX,NO_JOIN_INDEX,
ORDER_INDEX, NO_ORDER_INDEX는
다른 모든 optimizer 힌트보다 우선하며,
다른 index-level optimizer 힌트도 포함합니다.
다른 optimizer 힌트는 이들 힌트에 의해 허용된 인덱스에만
적용됩니다.
GROUP_INDEX,
INDEX, JOIN_INDEX,
ORDER_INDEX 힌트는 모두
USE INDEX가 아닌
FORCE INDEX와 동일합니다.
이는 이러한 힌트 중 하나 이상을 사용하면,
이름이 지정된 인덱스 중 하나를 사용하여
테이블에서 행을 찾을 수 있는 방법이 전혀 없는 경우에만
테이블 스캔이 사용되기 때문입니다.
주어진 USE INDEX 인스턴스와 동일한 인덱스 또는 인덱스 집합을
사용하도록 MySQL을 강제하려면,
NO_INDEX,
NO_JOIN_INDEX,
NO_GROUP_INDEX,
NO_ORDER_INDEX 또는 이들의 조합을
사용할 수 있습니다.
SELECT a,c FROM t1 USE INDEX FOR ORDER BY (i_a) ORDER BY a
쿼리에서 USE INDEX가 가지는 효과를
동일하게 만들기 위해서는,
다음과 같이 원하는 인덱스를 제외한
모든 인덱스에 대해
NO_ORDER_INDEX optimizer 힌트를 사용할 수 있습니다:
1SELECT /*+ NO_ORDER_INDEX(t1 i_b,i_c) */ a,c 2 FROM t1 3 ORDER BY a;
테이블 전체에 대해 NO_ORDER_INDEX를 사용하면서
USE INDEX FOR ORDER BY와 결합하려는 시도는
작동하지 않습니다.
그 이유는
NO_ORDER_BY가 USE INDEX를
무시하게 하기 때문입니다.
다음 예와 같이 동작합니다:
1mysql> EXPLAIN SELECT /*+ NO_ORDER_INDEX(t1) */ a,c FROM t1 2 -> USE INDEX FOR ORDER BY (i_a) ORDER BY a\G 3*************************** 1. row *************************** 4 id: 1 5 select_type: SIMPLE 6 table: t1 7 partitions: NULL 8 type: ALL 9possible_keys: NULL 10 key: NULL 11 key_len: NULL 12 ref: NULL 13 rows: 256 14 filtered: 100.00 15 Extra: Using filesort
USE INDEX, FORCE INDEX,
IGNORE INDEX 인덱스 힌트는
INDEX_MERGE 및
NO_INDEX_MERGE
optimizer 힌트보다 더 높은 우선순위를 가집니다.
1/*+ INDEX_MERGE(t1 i_a, i_b, i_c) */ ... IGNORE INDEX i_a
IGNORE INDEX가
INDEX_MERGE보다 우선하므로,
인덱스 i_a는 인덱스 머지용
가능한 range에서 제외됩니다.
1/*+ NO_INDEX_MERGE(t1 i_a, i_b) */ ... FORCE INDEX i_a, i_b
FORCE INDEX 때문에
i_a, i_b에 대한 인덱스 머지는 허용되지 않지만,
optimizer는
range 또는
ref 접근을 위해
i_a 또는 i_b를
반드시 사용해야 합니다.
이 경우 충돌은 없으며,
두 힌트 모두 적용 가능합니다.
IGNORE INDEX 힌트가 여러 인덱스를 지정하는 경우,
해당 인덱스는 인덱스 머지에 사용할 수 없습니다.
FORCE INDEX 및 USE INDEX 힌트는
이름이 지정된 인덱스만 인덱스 머지에 사용할 수 있도록 합니다.
1SELECT /*+ INDEX_MERGE(t1 i_a, i_b, i_c) */ a FROM t1 2FORCE INDEX (i_a, i_b) WHERE c = 'h' AND a = 2 AND b = 'b';
이 경우 (i_a, i_b)에 대해
인덱스 머지 intersection 접근 방식이 사용됩니다.
FORCE INDEX를
USE INDEX로 변경해도 결과는 동일합니다.
Subquery 힌트는 세미조인 변환을 사용할지 여부와
어떤 세미조인 전략을 허용할지에 영향을 주며,
세미조인이 사용되지 않을 경우
서브쿼리 구체화 또는
IN-to-EXISTS
변환을 사용할지 여부에 영향을 줍니다.
이러한 최적화에 대한 자세한 정보는
Section 10.2.2, “Optimizing Subqueries, Derived Tables, View References, and Common Table Expressions”을
참조하십시오.
세미조인 전략에 영향을 미치는 힌트의 구문:
1hint_name([@query_block_name] [strategy [, strategy] ...])
구문은 다음 용어를 참조합니다:
hint_name: 다음 힌트 이름이
허용됩니다:
SEMIJOIN,
NO_SEMIJOIN:
지정된 세미조인 전략을 활성화 또는 비활성화합니다.strategy: 활성화 또는 비활성화할
세미조인 전략입니다.
다음 전략 이름이 허용됩니다:
DUPSWEEDOUT,
FIRSTMATCH,
LOOSESCAN,
MATERIALIZATION.
SEMIJOIN 힌트의 경우,
전략이 지정되지 않으면
optimizer_switch 시스템
변수에 의해 활성화된 전략에 기반하여
가능하다면 세미조인이 사용됩니다.
전략이 지정되었으나 문장에 적용 불가능한 경우,
DUPSWEEDOUT가 사용됩니다.
NO_SEMIJOIN 힌트의 경우,
전략이 지정되지 않으면 세미조인은 사용되지 않습니다.
전략이 지정되었고 그로 인해
문장에 적용 가능한 모든 전략이 배제되는 경우,
DUPSWEEDOUT가 사용됩니다.
어떤 서브쿼리가 다른 서브쿼리 안에 중첩되어 있고
이 둘이 모두 outer 쿼리의 세미조인으로 merge되는 경우,
가장 안쪽 쿼리에 대해 지정된 세미조인 전략은
무시됩니다.
이러한 중첩 서브쿼리에 대해서도
SEMIJOIN 및
NO_SEMIJOIN 힌트를 사용하여
세미조인 변환을 활성화 또는 비활성화할 수 있습니다.
DUPSWEEDOUT가 비활성화된 경우,
optimizer가 매우 비효율적인 쿼리 플랜을
생성하는 경우가 가끔 있습니다.
이는 greedy 탐색 중 휴리스틱 가지치기(pruning)로 인해 발생하며,
optimizer_prune_level=0을 설정하여
회피할 수 있습니다.
예:
1SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, LOOSESCAN) */ * FROM t2 2 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3); 3SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION, DUPSWEEDOUT) */ * FROM t2 4 WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
Subquery 구체화 또는
IN-to-EXISTS
변환 사용 여부에 영향을 미치는 힌트의 구문:
1SUBQUERY([@query_block_name] strategy)
힌트 이름은 항상
SUBQUERY입니다.
SUBQUERY 힌트의 경우,
허용되는 strategy 값은
INTOEXISTS,
MATERIALIZATION입니다.
예:
1SELECT id, a IN (SELECT /*+ SUBQUERY(MATERIALIZATION) */ a FROM t1) FROM t2; 2SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ SUBQUERY(INTOEXISTS) */ a FROM t1);
세미조인 및 SUBQUERY
힌트의 경우,
선행 @query_block_name은
힌트가 적용되는 쿼리 블록을 지정합니다.
힌트에 선행
@query_block_name이 없으면,
힌트는 그것이 포함된 쿼리 블록에 적용됩니다.
쿼리 블록에 이름을 할당하는 방법은
Optimizer Hints for Naming Query Blocks를 참조하십시오.
힌트 주석에 여러 서브쿼리 힌트가 포함된 경우, 첫 번째 힌트가 사용됩니다. 그 다음에 같은 유형의 힌트가 있으면 경고가 발생합니다. 그 외 다른 유형의 이후 힌트는 조용히 무시됩니다.
MAX_EXECUTION_TIME 힌트는
SELECT
문장에서만 허용됩니다.
이 힌트는 문장이 서버에 의해 종료되기 전에
실행될 수 있는 시간을
N 밀리초 단위의 타임아웃 값으로 제한합니다:
1MAX_EXECUTION_TIME(N)
1초(1000밀리초) 타임아웃 예:
1SELECT /*+ MAX_EXECUTION_TIME(1000) */ * FROM t1 INNER JOIN t2 WHERE ...
MAX_EXECUTION_TIME(N)
힌트는 해당 문장의 실행 타임아웃을
N 밀리초로 설정합니다.
이 옵션이 없거나 _N_이 0이면,
max_execution_time 시스템
변수에 의해 설정된 문장 타임아웃이 적용됩니다.
MAX_EXECUTION_TIME 힌트는
다음과 같이 적용됩니다:
union 또는 서브쿼리를 포함하는 문장 등
여러 개의 SELECT 키워드를 가지는 문장의 경우,
MAX_EXECUTION_TIME는
전체 문장에 적용되며
첫 번째 SELECT 뒤에
나타나야 합니다.
이 힌트는 읽기 전용
SELECT 문장에 적용됩니다.
읽기 전용이 아닌 문장은
데이터를 부수 효과로 수정하는 저장 함수(stored function)를 호출하는
문장입니다.
저장 프로그램 내의
SELECT 문장에는 적용되지 않으며,
무시됩니다.
SET_VAR 힌트는
하나의 문장 기간 동안만
시스템 변수의 세션 값을 일시적으로 설정합니다.
예:
1SELECT /*+ SET_VAR(sort_buffer_size = 16M) */ name FROM people ORDER BY name; 2INSERT /*+ SET_VAR(foreign_key_checks=OFF) */ INTO t2 VALUES(2); 3SELECT /*+ SET_VAR(optimizer_switch = 'mrr_cost_based=off') */ 1;
SET_VAR 힌트의 구문:
1SET_VAR(var_name = value)
_var_name_은 세션 값을 가지는
시스템 변수의 이름입니다
(단, 이후에 설명하듯 모든 변수를 지정할 수 있는 것은 아닙니다).
_value_는 변수에 할당할 값으로,
스칼라 값이어야 합니다.
SET_VAR는
다음 문장에서 볼 수 있듯
변수를 일시적으로 변경합니다:
1mysql> SELECT @@unique_checks; 2+-----------------+ 3| @@unique_checks | 4+-----------------+ 5| 1 | 6+-----------------+ 7mysql> SELECT /*+ SET_VAR(unique_checks=OFF) */ @@unique_checks; 8+-----------------+ 9| @@unique_checks | 10+-----------------+ 11| 0 | 12+-----------------+ 13mysql> SELECT @@unique_checks; 14+-----------------+ 15| @@unique_checks | 16+-----------------+ 17| 1 | 18+-----------------+
SET_VAR를 사용하면
변수 값을 저장하고 복원할 필요가 없습니다.
이를 통해 여러 문장을 하나의 문장으로
대체할 수 있습니다.
다음 문장 시퀀스를 고려해 보십시오:
1SET @saved_val = @@SESSION.var_name; 2SET @@SESSION.var_name = value; 3SELECT ... 4SET @@SESSION.var_name = @saved_val;
이 시퀀스는 다음과 같은 단일 문장으로 대체될 수 있습니다:
1SELECT /*+ SET_VAR(var_name = value) ...
독립적인
SET
문장은 세션 변수 이름을 지정하기 위해
다음 구문 중 하나를 허용합니다:
1SET SESSION var_name = value; 2SET @@SESSION.var_name = value; 3SET @@.var_name = value;
SET_VAR 힌트는
세션 변수에만 적용되므로
세션 범위가 암시적입니다.
따라서 SESSION, @@SESSION.,
@@는 필요도 없고 허용도 되지 않습니다.
명시적인 세션 표시 구문을 포함하면
SET_VAR 힌트는
경고와 함께 무시됩니다.
모든 세션 변수가
SET_VAR에서
사용 가능한 것은 아닙니다.
각 시스템 변수 설명에
해당 변수가 힌트로 사용 가능한지 여부가 표시됩니다
( Section 7.1.8, “Server System Variables” 참조).
또는 런타임에 해당 시스템 변수를
SET_VAR와 함께 사용해 보아도 됩니다.
변수가 힌트로 사용할 수 없는 경우 경고가 발생합니다:
1mysql> SELECT /*+ SET_VAR(collation_server = 'utf8mb4') */ 1; 2+---+ 3| 1 | 4+---+ 5| 1 | 6+---+ 71 row in set, 1 warning (0.00 sec) 8 9mysql> SHOW WARNINGS\G 10*************************** 1. row *************************** 11 Level: Warning 12 Code: 4537 13Message: Variable 'collation_server' cannot be set using SET_VAR hint.
SET_VAR 구문은
하나의 변수만 설정할 수 있지만,
여러 힌트를 사용하여 여러 변수를 설정할 수 있습니다:
1SELECT /*+ SET_VAR(optimizer_switch = 'mrr_cost_based=off') 2 SET_VAR(max_heap_table_size = 1G) */ 1;
같은 문장에 동일한 변수 이름을 가진 힌트가 여러 개 있는 경우, 첫 번째 힌트가 적용되고 나머지는 경고와 함께 무시됩니다:
1SELECT /*+ SET_VAR(max_heap_table_size = 1G) 2 SET_VAR(max_heap_table_size = 3G) */ 1;
이 경우 두 번째 힌트는 충돌한다는 경고와 함께 무시됩니다.
시스템 변수 이름이 잘못되었거나
변수 값이 잘못된 경우,
SET_VAR 힌트는
경고와 함께 무시됩니다:
1SELECT /*+ SET_VAR(max_size = 1G) */ 1; 2SELECT /*+ SET_VAR(optimizer_switch = 'mrr_cost_based=yes') */ 1;
첫 번째 문장에서는
max_size 변수가 존재하지 않습니다.
두 번째 문장에서는
mrr_cost_based가
on 또는 off 값을 취하므로,
이를 yes로 설정하려는 시도는 잘못되었습니다.
두 경우 모두 힌트는 경고와 함께
무시됩니다.
SET_VAR 힌트는
문장 수준에서만 허용됩니다.
서브쿼리에서 사용되면
경고와 함께 무시됩니다.
Replica는 보안 문제 가능성을 피하기 위해
복제된 문장에서
SET_VAR 힌트를
무시합니다.
RESOURCE_GROUP optimizer
힌트는 리소스 그룹 관리에 사용됩니다
( Section 7.1.16, “Resource Groups” 참조).
이 힌트는 문장을 실행하는 스레드를
문장 실행 기간 동안만
지정된 리소스 그룹에 할당합니다.
이를 위해서는
RESOURCE_GROUP_ADMIN 또는
RESOURCE_GROUP_USER 권한이 필요합니다.
예:
1SELECT /*+ RESOURCE_GROUP(USR_default) */ name FROM people ORDER BY name; 2INSERT /*+ RESOURCE_GROUP(Batch) */ INTO t2 VALUES(2);
RESOURCE_GROUP
힌트의 구문:
1RESOURCE_GROUP(group_name)
_group_name_은 스레드가
문장 실행 기간 동안 할당되어야 하는
리소스 그룹을 나타냅니다.
그룹이 존재하지 않으면 경고가 발생하고
힌트는 무시됩니다.
RESOURCE_GROUP 힌트는
문장의 초기 키워드
(SELECT, INSERT,
REPLACE, UPDATE,
DELETE) 뒤에 나타나야 합니다.
RESOURCE_GROUP의
대안은
SET RESOURCE GROUP 문장입니다.
이 문장은 스레드를 리소스 그룹에
일시적이 아닌 방식으로 할당합니다.
자세한 내용은
Section 15.7.2.4, “SET RESOURCE GROUP Statement”를
참조하십시오.
Table-level, index-level, subquery optimizer 힌트는
인수 구문의 일부로
특정 쿼리 블록 이름을 지정하도록 허용합니다.
이 이름을 생성하려면,
해당 쿼리 블록에 이름을 할당하는
QB_NAME 힌트를 사용하십시오:
1QB_NAME(name)
QB_NAME 힌트는
다른 힌트가 어떤 쿼리 블록에 적용되는지
명확하게 표현하는 데 사용할 수 있습니다.
또한 모든 비-쿼리 블록 이름 힌트를
단일 힌트 주석 내에 지정할 수 있게 하여,
복잡한 문장을 더 쉽게 이해할 수 있도록 합니다.
다음 문장을 고려해 보십시오:
1SELECT ... 2 FROM (SELECT ... 3 FROM (SELECT ... FROM ...)) ...
QB_NAME 힌트는
문장 내 쿼리 블록에 이름을 할당합니다:
1SELECT /*+ QB_NAME(qb1) */ ... 2 FROM (SELECT /*+ QB_NAME(qb2) */ ... 3 FROM (SELECT /*+ QB_NAME(qb3) */ ... FROM ...)) ...
그런 다음 다른 힌트는 이러한 이름을 사용하여 적절한 쿼리 블록을 참조할 수 있습니다:
1SELECT /*+ QB_NAME(qb1) MRR(@qb1 t1) BKA(@qb2) NO_MRR(@qb3t1 idx1, id2) */ ... 2 FROM (SELECT /*+ QB_NAME(qb2) */ ... 3 FROM (SELECT /*+ QB_NAME(qb3) */ ... FROM ...)) ...
이때 결과 효과는 다음과 같습니다:
MRR(@qb1 t1)는
쿼리 블록 qb1의
테이블 t1에 적용됩니다.
BKA(@qb2)는
쿼리 블록 qb2에 적용됩니다.
NO_MRR(@qb3 t1 idx1, id2)는
쿼리 블록 qb3의
테이블 t1에 있는
인덱스 idx1 및 idx2에
적용됩니다.
쿼리 블록 이름은 식별자이며, 유효한 이름과 인용 방식에 대한 일반적인 규칙을 따릅니다 ( Section 11.2, “Schema Object Names” 참조). 예를 들어, 공백을 포함하는 쿼리 블록 이름은 backtick을 사용해 인용해야 합니다:
1SELECT /*+ BKA(@`my hint name`) */ ... 2 FROM (SELECT /*+ QB_NAME(`my hint name`) */ ...) ...
ANSI_QUOTES SQL 모드가
활성화된 경우, 쿼리 블록 이름을
double quote로 감싸서 인용할 수도 있습니다:
1SELECT /*+ BKA(@"my hint name") */ ... 2 FROM (SELECT /*+ QB_NAME("my hint name") */ ...) ...
10.9.2 Switchable Optimizations
10.9.4 Index Hints