Index Fast Full Scan 은 Table Full Scan의 Index Version 이라고 할 수 있다.
Table Full Scan 이 Table Segment 를 처음부터 끝(HWM) 까지 읽는 Operation 이라면,
Index Fast Full Scan 은 Index Segment 를 처름부터 끝(HW)까지 읽으면서 그 중에서
Leaf Block 에 존재하는 Key 값을 Operation 이다.
[ Root / Branch / Leaf 모두 다 읽는다는 의미 - 정렬 안해서.. ]
Index Fast Full Scan 의 특징을 한마디로 표현하면
"Index Key 를 모두 읽는 Operation 중 가장 효율적인 Operation" 이다.
Why ? [ 내 추측 ]
Index Full Scan - 정렬해서 [ Ordering 작업 여기갔다가 저기 갔다가...] - Single I/O
Index Fast Full Scan - 그냥 해당 Index Segment 에 해당하는 Block 을 쭉~욱 읽는다. - Multi Block I/O
Oracle 자신도 Index Key 를 모두 읽는 목적으로 Index Fast Full Scan 을 사용한다.
가령 Index를 Rebuild(alter Index .. rebuild)하는 경우,
Oracle 은 원본 Index 를 Index Fast Full Scan 으로 읽어 들이면서 새롭게 Index를 재구축한다.
h3. \*Index Full Scan VS Index Fast Full Scan\*
Index Full | ScanIndex Fast Full Scan | |
---|---|---|
I/O 방식 | Single Block I/O | Multi Block I/O |
정렬 | 정렬 보장 | 정렬 안됨 |
속도 | 느림 | 빠름 |
병렬읽기 | 지원안됨 | 지원됨 |
Index Fast Full Scan 이 Table Full Scan 과 동일한 방식의 Multi Block I/O 를
사용한다는 것이 핵심이다. Multi Block I/O 를 사용하기 때문에 정렬이 보장이
안되고, 그 만큼 속도는 빠르다. 자연스럽게도 Parallel Query 도 지원된다.
Index Range Scan / Index Full Scan 은 기본적으로 Parallel Scan 이 지원되지 않는다.
\*단. Partition Index에 대해 PARALLEL_INDEX Hint를 사용하는 경우에는 Rarallel Range Scan 이 가능하다.\*
Parallel Index Fast Full Scan
SYS>drop table t1 purge ;
Table dropped.
SYS>create table t1 (c1 int, c2 int)
partition by hash (c1)
partitions 4 ;
Table created.
SYS>create index t1_n1 on t1(c1) local ;
Index created.
SYS>insert into t1 select level, level from dual connect by level <= 10000 ;
10000 rows created.
SYS>commit ;
Commit complete.
SYS>@gather t1
PL/SQL procedure successfully completed.
SYS>explain plan for select /\* index_ffs(t1) \*/ c1 from t1 where c1 > 0 ;
Explained.
SYS>@plan
PLAN_TABLE_OUTPUT
\------------------------------------------------------------------------------------------------\-
Plan hash value: 2434397737
\----------------------------------------------------------------------------------------------\-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time | Pstart | Pstop |
\----------------------------------------------------------------------------------------------\-
| 0 | SELECT STATEMENT | | 10000 | 40000 | 6 (0) | 00:00:01 | | |
| 1 | PARTITION HASH ALL | | 10000 | 40000 | 6 (0) | 00:00:01 | 1 | 4 |
| * 2 | INDEX FAST FULL SCAN | T1_N1 | 10000 | 40000 | 6 (0) | 00:00:01 | 1 | 4 |
\----------------------------------------------------------------------------------------------\-
\--> Pstart / Pstop 해석을 어떻게 함 ㅇㅇ? 파티션 1에서 4까지 ?
Predicate Information (identified by operation id):
\--------------------------------------------------\-
2 - filter("C1">0)
14 rows selected.
SYS> select /*\+ gahter_plan_statistics index_ffs(t1) \*/ c1 from t1 where c1 > 0
10000 rows selected.
==> 실제 리턴되는 결과는 정렬되지 않고 Return 된다.
SYS>@stat
PLAN_TABLE_OUTPUT
\--------------------------------------------------------------------------------\-
SQL_ID 3tjq2pqgay4z0, child number 0
\------------------------------------\-
select /*\+ gahter_plan_statistics index_ffs(t1) \*/ c1 from t1 where c1
> 0
Plan hash value: 2434397737
\------------------------------------------------------------\-
| Id | Operation | Name | E-Rows | Cost (%CPU) |
\------------------------------------------------------------\-
| 1 | PARTITION HASH ALL | | 10000 | 6 (0) |
| * 2 | INDEX FAST FULL SCAN | T1_N1 | 10000 | 6 (0) |
\------------------------------------------------------------\-
Predicate Information (identified by operation id):
\--------------------------------------------------\-
2 - filter("C1">0)
Note
- Warning: basic plan statistics not available. These are only collected when:
* hint 'gather_plan_statistics' is used for the statement or
* parameter 'statistics_level' is set to 'ALL', at session or system level
25 rows selected.
Paralle Index Fast Full Scan 을 수행하려면 어떻게 해야 할까 ?
다음과 같이 PARALLE Hint를 부여하면 ?
실망스럽게도 Parallel Execution 이 선택되지 않는다.
이유는 간단하다. PARALLEL Hint 는 Table 에 대해서만 적용되기 때문이다.
\*Index Fast Full Scan 을 Paralle Execution 으로 전환하는 방법은 Index Object 에
PARALLEL 속성을 부여하거나 PARALLEL_INDEX Hint 를 사용하는 것이다.\*
SYS>explain plan for select /*\+ index_ffs(t1) parallel(t1) \*/ c1 from t1 where c1 > 0 ;
Explained.
SYS>@plan
PLAN_TABLE_OUTPUT
\----------------------------------------------------------------------------------------------\-
Plan hash value: 2434397737
\----------------------------------------------------------------------------------------------\-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time | Pstart | Pstop |
\----------------------------------------------------------------------------------------------\-
| 0 | SELECT STATEMENT | | 10000 | 40000 | 6 (0) | 00:00:01 | | |
| 1 | PARTITION HASH ALL | | 10000 | 40000 | 6 (0) | 00:00:01 | 1 | 4 |
| * 2 | INDEX FAST FULL SCAN | T1_N1 | 10000 | 40000 | 6 (0) | 00:00:01 | 1 | 4 |
\----------------------------------------------------------------------------------------------\-
Predicate Information (identified by operation id):
\--------------------------------------------------\-
2 - filter("C1">0)
14 rows selected.
SYS>alter index t1_n1 parallel ;
Index altered.
SYS>explain plan for select /*\+ index_ffs(t1) \*/ c1 from t1 where c1 > 0 ;
Explained.
SYS>@plan
PLAN_TABLE_OUTPUT
\--------------------------------------------------------------------------------------------------------------------------------\-
Plan hash value: 3351752447
\--------------------------------------------------------------------------------------------------------------------------------\-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time | Pstart | Pstop | TQ | IN-OUT | PQ Distrib |
\--------------------------------------------------------------------------------------------------------------------------------\-
| 0 | SELECT STATEMENT | | 10000 | 40000 | 6 (0) | 00:00:01 | | | | | |
| 1 | PX COORDINATOR | | | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10000 | 10000 | 40000 | 6 (0) | 00:00:01 | | | Q1,00 | P->S | QC (RAND) |
| 3 | PX BLOCK ITERATOR | | 10000 | 40000 | 6 (0) | 00:00:01 | 1 | 4 | Q1,00 | PCWC | |
| * 4 | INDEX FAST FULL SCAN | T1_N1 | 10000 | 40000 | 6 (0) | 00:00:01 | 1 | 4 | Q1,00 | PCWP | |
\--------------------------------------------------------------------------------------------------------------------------------\-
Predicate Information (identified by operation id):
\--------------------------------------------------\-
4 - filter("C1">0)
16 rows selected.
PARALLEL_INDEX Hint 사용해서 Index Parallel 처리
SQL> explain plan for select /*+ index_ffs(t1) parallel_index(t1 t1_n1) */ c1 from t1 where c1 > 0 ;
Explained.
SQL> @plan
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Pstart| Pstop | TQ |IN-OUT| PQ Distrib |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10000 | 40000 | 6 (0)| | | | | |
| 1 | PX COORDINATOR | | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10000 | 10000 | 40000 | 6 (0)| | | Q1,00 | P->S | QC (RAND) |
| 3 | PX BLOCK ITERATOR | | 10000 | 40000 | 6 (0)| 1 | 4 | Q1,00 | PCWC | |
|* 4 | INDEX FAST FULL SCAN| T1_N1 | 10000 | 40000 | 6 (0)| 1 | 4 | Q1,00 | PCWP | |
-------------------------------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter("C1">0)
Note
-----
- 'PLAN_TABLE' is old version
19 rows selected.
: Query 변형이 없음
1) 흔히 말하는 제공자 SubQuery임
: SubQuery 부터 풀려서 MainQuery 에 값이 제공된다.
: Query 의 변형이 없음
1) 흔히 말하는 확인자 SubQuery임
: Main Query 의 값을 제공받아 SubQuery 에서 Check 하는 방식임
==> Main Query 가 먼저 수행된 값을 받아 Checkg 하는 쿼리일때는 Filter
근데 테스트 후반에 가면 2개가 같이 나오는 경우가 많다.
무슨 의미일까 ?
SYS>explain plan for select /*\+ index_ffs(t1) parallel_index(t1 t1_n1) \*/ c1 from t1 where c1 > 0 ;
Explained.
SYS>@plan
PLAN_TABLE_OUTPUT
\-------------------------------------------------------------------------------------------------------------------------------\-
Plan hash value: 3351752447
\--------------------------------------------------------------------------------------------------------------------------------\-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time | Pstart | Pstop | TQ | IN-OUT | PQ Distrib |
\--------------------------------------------------------------------------------------------------------------------------------\-
| 0 | SELECT STATEMENT | | 10000 | 40000 | 6 (0) | 00:00:01 | | | | | |
| 1 | PX COORDINATOR | | | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10000 | 10000 | 40000 | 6 (0) | 00:00:01 | | | Q1,00 | P->S | QC (RAND) |
| 3 | PX BLOCK ITERATOR | | 10000 | 40000 | 6 (0) | 00:00:01 | 1 | 4 | Q1,00 | PCWC | |
| * 4 | INDEX FAST FULL SCAN | T1_N1 | 10000 | 40000 | 6 (0) | 00:00:01 | 1 | 4 | Q1,00 | PCWP | |
\--------------------------------------------------------------------------------------------------------------------------------\-
Predicate Information (identified by operation id):
\--------------------------------------------------\-
4 - filter("C1">0)
16 rows selected.
Index Fast Full Scan 은 INDEX_FFS Hint 를 이용해 제어 한다.
select /*\+ index_ffs(t1) \*/ c1 from t1 ;
select /*\+ index_ffs(t1 t1_n1) \*/ c1 from t1 ;
select /*\+ index_ffs(t1 t1(c1)) \*/ c1 from t1;
Index Fast Full Scan의 동작 여부는 \_FAST_FULL_SCAN_ENABLED Parameter 를 통해
제어 가능하다.
SYS>@check_hidden_parameter.sql
Enter value for input_parameter: \_fast_full_scan_enabled
old 15: a.ksppinm LIKE '&input_parameter'
new 15: a.ksppinm LIKE '_fast_full_scan_enabled'
Parameter Session Value Instance Value
\-----------------------------------------------------------\- \-----------------------------\- \-----------------------------\-
\_fast_full_scan_enabled TRUE TRUE
\_FAST_FULL_SCAN_ENABLED
이 값이 TRUE일 경우 Index에 대한 DB_FILE_MULTIBLOCK_READ_COUNT를 통한 Full
Scan을 가능하도록 한다. 단 Index의 해당 Column에는 Not Null과 해당 Column이 모두
Index로 구성이 되어야 한다.