4. 응용 변형 예제
예제 6: 힌트 주석은 H2 에서 무시된다
Oracle 힌트를 넣은 쿼리를 H2 로 실행하면 오류 없이 돌고 결과가 같습니다. 힌트가 효과를 냈다는 뜻이 아니라 H2 가 주석으로 취급했다는 뜻입니다.
SELECT /*+ INDEX(o idx_orders_status) */ COUNT(*) AS cnt FROM orders o WHERE o.status = 'CANCEL';CNT
---
50
(1행)힌트를 뺀 같은 쿼리도 50 이었습니다. 힌트는 계획을 바꿀 뿐 결과를 바꾸지 않는 것이 원칙이라 결과는 같아야 합니다.
SELECT /*+ INDEX(x no_such_index) */ COUNT(*) AS cnt FROM orders o WHERE o.status = 'CANCEL';CNT
---
50
(1행)별칭 x 도 없고 없는 인덱스 이름인데 오류가 나지 않았습니다. H2 는 힌트를 읽지 않기 때문입니다.
주의실제 Oracle 도 힌트 문법이 틀리거나 별칭이 안 맞으면 오류 없이 힌트를 무시합니다. 힌트를 쓴 뒤에는 실행 계획으로 실제로 적용됐는지 확인해야 합니다. 힌트에서 표를 가리킬 때는 FROM 에 쓴 별칭을 씁니다.
예제 7: DB별 힌트 문법 (문법 검토만)
같은 뜻을 DB별로 쓰면 아래와 같습니다. 문법 검토만 한 것이며 실행하지 않았습니다.
-- Oracle · Tibero
SELECT /*+ INDEX(o idx_orders_status) */
COUNT(*)
FROM orders o
WHERE o.status = 'CANCEL';
SELECT /*+ FULL(o) */
COUNT(*)
FROM orders o
WHERE o.status = 'DONE';-- MySQL
SELECT COUNT(*) FROM orders o FORCE INDEX (idx_orders_status) WHERE o.status = 'CANCEL';
SELECT COUNT(*) FROM orders o IGNORE INDEX (idx_orders_status) WHERE o.status = 'DONE';-- MSSQL
SELECT COUNT(*) FROM orders o WITH (INDEX(idx_orders_status)) WHERE o.status = 'CANCEL';
SELECT COUNT(*) FROM orders o WHERE o.status = 'DONE' OPTION (RECOMPILE);Oracle 의 FULL(o) 는 전체 읽기 지시입니다. 95% 를 읽는 DONE 조회는 인덱스보다 전체 읽기가 낫습니다. MySQL 의 FORCE INDEX 는 전체 읽기보다 지정한 인덱스를 쓰라는 강한 지시이고, IGNORE INDEX 는 지정한 인덱스를 못 쓰게 합니다. MSSQL 의 OPTION (RECOMPILE) 은 실행마다 계획을 다시 세워 파라미터 스니핑을 피합니다.
예제 8: 통계를 고친 뒤의 계획 (도식, H2 미지원)
통계를 다시 모은 뒤 같은 쿼리의 계획은 실제 분포에 맞게 바뀝니다. 수집 명령은 2.4 절의 GATHER_TABLE_STATS 입니다.
도식(H2 미지원, 실행 결과 아님)
| Id | Operation | Name | E-Rows | A-Rows |
-------------------------------------------------------
| 0 | SELECT STATEMENT | | | 1 |
| 1 | SORT AGGREGATE | | 1 | 1 |
|* 2 | TABLE ACCESS FULL| ORDERS | 20050 | 20050 |E-Rows 와 A-Rows 가 같아졌고 계획은 전체 읽기입니다. 취소가 80% 인 상황에서는 이 계획이 맞습니다. 힌트로 인덱스를 강제했다면 데이터가 이렇게 바뀐 뒤에도 느린 계획이 계속됐을 것입니다.