h3.(1) 인덱스 파티션 유형
① 비파티션 인덱스(Non-Partitioned Index)
② 글로벌 파티션 인덱스(Global Partitioned Index)
③ 로컬 파티션 인덱스(Local Partitioned Index)
h3.(2) 로컬 파티션 인덱스
① 각 인덱스 파티션이 테이블 파티션과 1:1 대응 관계를 가지며, 테이블 파티션 속성을 그대로 상속받는다.
② 파티션 키를 사용자가 따로 정의하지 않아도 오라클이 자동으로 관리
③ 테이블 파티션과 1:1 관계가 되도록 사용자가 수동으로 인덱스 파티션을 구성하더라도 이를 로컬 파티션 인덱스라고 부르지 않는다.
④ 테이블이 결합 파티셔닝 돼 있다면 인덱스도 같은 단위로 파티셔닝
⑤ 테이블 파티션 구성에 변경이 생기더라도 인덱스를 재생성할 필요가 없다.
h3.(3) 비 파티션 인덱스
① 파티셔닝하지 않은 인덱스
② 1:M 관계
③ 하나의 인덱스 세그먼트가 여러 테이블 파티션 세그먼트와 관계
④ '글로벌 비파티션 인덱스'라 부르기도 한다.
① 테이블 파티션과 독립적인 구성을 갖도록 파티셔닝하는 것
② 테이블은 파티셔닝돼 있지 않을 수도 있다.
③ 기준 테이블의 파티션 구성에 변경(drop, exchange, split등)이 생길 때마다 인덱스가 unusable 상태로 바뀌고 그때마다
인덱스를 재생성해야 한다. (비파티션 인덱스일 때도 동일)
④ 9i부터 update global indexes 옵션을 주면 파티션 DDL 작업에 의해 영향을 받는 인덱스 레코드를 자동으로 갱신해 준다.
(unusable 상태로 빠지지 않는다)
alter table ...
split partition ...
update global indexes;
- 파티션 DDL로 인해 영향 받는 레코드가 전체의 5% 미만일 때만 유용
① "오라클이 자동으로 관리해 주는 1:1 관계"가 아닌 파티션 인덱스는 모두 글로벌 파티션 인덱스
② 하나의 인덱스 파티션이 여러 테이블 파티션과 관계를 갖고, 반대로 하나의 테이블 파티션이 여러 인덱스 파티션과 관계를 갖는다.
③ 로컬 파티션 인덱스처럼 테이블과 1:1 관계가 되도록 수동으로 구성하더라도 글로벌 파티션과 마찬가지로 기준 테이블 구성에 변경이
발생할 때마다 인덱스를 재생성해야 한다.
④ 인덱스를 테이블 파티션과 다른 키 컬럼으로 글로벌 파티셔닝(테이블은 주문일자, 인덱스는 배송일자)할 수도 있는데, 이때는 테이블
파티션과 인덱스 파티션 간에는 항상 M:M 관계가 형성.
① 10g부터는 글로벌 해시 파티션도 가능.
② 테이블과 독립적으로 인덱스만 해시 키 값에 따라 파티셔닝할 수 있다.
③ 글로벌 해시 파티션 인덱스는 Right Growing 인덱스처러 Hot 블록이 발생하는 인덱스의 경합을 분산할 목적으로 주로 사용
① 인덱스 파티션 키 컬럼이 인덱스 구성상 왼쪽 선두 컬럼에 위치하는지에 따른 구분
② 글로벌 파티션 인덱스는 Prefixed 파티션만 지원
③ 인덱스 유형
SQL >
l create table t ( gubun
2 , seq, seq_name, seq_cls
3 , seq2, seq2_name, seq2_cls
4 )
5 partition by range(seq) (
6 partition p1 values less than(100)
7 , partition p2 values less than(200)
8 , partition p3 values less than(300)
9 , partition p4 values less than(maxvalue)
10 )
11 as
12 select 1
13 , rownum, dbms_random.string('u', 10), 'A'
14 , round(dbms_random.value(1, 400)), dbms_random.string('l', 10), 'B'
15 from dual
16 connect by level <= 400 ;
테이블이 생성되었습니다.
- seq 컬럼 기준으로 Range 파티셔닝
SQL> create unique index t_idx1 on t(gubun, seq2) LOCAL ;
create unique index t_idx1 on t(gubun, seq2) LOCAL
*
1행에 오류:
ORA-14039: 열을 분할영역한 것은 UNIQUE 인덱스로 키 열의 부분 집합을 폼 합니다
- Unique 파티션 인덱스를 만들 때는 파티션 키 컬럼이 인덱스 컬럼에 포함돼 있어야 한다.
SQL> create unique index t_idx1 on t(gubun, seq2) ;
인덱스가 생성되었습니다.
- 비파티션 인덱스를 만들 때는 그런 제약이 없다.
SQL> create unique index t_idx2 on t(gubun, seq) LOCAL ;
인덱스가 생성되었습니다.
- 파티션 키를 인덱스 구성 컬럼에 포함시켜 unique 인덱스 생성
SQL> create index t_idx3 on t(seq, gubun) LOCAL ;
인덱스가 생성되었습니다.
- 로컬 prefixed 파티션 인덱스 생성
SQL> create index t_idx4 on t(seq_name, seq) LOCAL ;
인덱스가 생성되었습니다.
- 로컬 Nonprefixed 파티션 인덱스 생성
SQL>
l create index t_idx5 on t(seq_cls, seq) GLOBAL
2 partition by range(seq) (
3 partition p1 values less than(100)
4 , partition p2 values less than(200)
5 , partition p3 values less than(300)
6 , partition p4 values less than(maxvalue)
7 )
8 ;
partition by range(seq) (
*
2행에 오류:
ORA-14038: GLOBAL로 분할영역된 인덱스는 접두사이어야 합니다
- 글로벌 파티션 인덱스에는 Nonprefixed 인덱스가 허용되지 않는다.
SQL>
l create index t_idx5 on t(seq, seq_cls) GLOBAL
2 partition by range(seq) (
3 partition p1 values less than(100)
4 , partition p2 values less than(200)
5 , partition p3 values less than(300)
6 , partition p4 values less than(maxvalue)
7 ) ;
인덱스가 생성되었습니다.
- 글로벌 Prefixed 파티션 인덱스 생성
- 테이블 파티션과 100% 같게 정의하더라도 이를 '로컬 파티션 인덱스'라고 부르지 않는다.
SQL>
l create index t_idx6 on t(seq, seq_name) GLOBAL
2 partition by range(seq) (
3 partition p1 values less than(200)
4 , partition p2 values less than(maxvalue)
5 ) ;
인덱스가 생성되었습니다.
- 각 인덱스 파티션이 두 개 테이블 파티션과 매핑
SQL>
l create index t_idx7 on t(seq, seq_name, seq_cls) GLOBAL
2 partition by range(seq) (
3 partition p1 values less than(50)
4 , partition p2 values less than(100)
5 , partition p3 values less than(150)
6 , partition p4 values less than(200)
7 , partition p5 values less than(250)
8 , partition p6 values less than(300)
9 , partition p7 values less than(350)
10 , partition p8 values less than(maxvalue)
11 ) ;
인덱스가 생성되었습니다.
- 두 개 인덱스 파티션이 한 개 테이블 파티션과 매핑되는 구조
SQL>
l create index t_idx8 on t(seq2) GLOBAL
2 partition by range(seq2) (
3 partition p1 values less than(100)
4 , partition p2 values less than(200)
5 , partition p3 values less than(300)
6 , partition p4 values less than(maxvalue)
7 ) ;
인덱스가 생성되었습니다.
- 테이블과 다른 컬럼으로 파티셔닝할 때는 항상 M:M 관계 형성
SQL>
l select i.index_name, i.uniqueness, p.locality
2 , p.alignment, i.partitioned, p.partition_count
3 from user_indexes i, user_part_indexes p
4 where i.table_name = 'T'
5 and p.table_name(+) = i.table_name
6 and p.index_name(+) = i.index_name
7 order by 1 ;
INDEX_NAME UNIQUENES LOCALI ALIGNMENT PAR PARTITION_COUNT
------------------------------ --------- ------ ------------ --- ---------------
T_IDX1 UNIQUE NO
T_IDX2 UNIQUE LOCAL NON_PREFIXED YES 4
T_IDX3 NONUNIQUE LOCAL PREFIXED YES 4
T_IDX4 NONUNIQUE LOCAL NON_PREFIXED YES 4
T_IDX5 NONUNIQUE GLOBAL PREFIXED YES 4
T_IDX6 NONUNIQUE GLOBAL PREFIXED YES 2
T_IDX7 NONUNIQUE GLOBAL PREFIXED YES 8
T_IDX8 NONUNIQUE GLOBAL PREFIXED YES 4
8 개의 행이 선택되었습니다.
① 글로벌 파티션 인덱스는 경합을 분산시키려고 글로벌 해시 파티셔닝하는 경우 외 에는 거의 사용하지 않는 실정이다.
② 테이블을 파티셔닝하지 않을 정도로 중소형급 테이블이면 굳이 인덱스만을 따로 파티셔닝 할 이유는 없다.
1) 테이블과 같은 컬럼으로 파티셔닝하는 경우
2) 테이블과 다른 컬럼으로 파티셔닝하는 경우
h3.(8) 로컬 Nonprefixed 파티션 인덱스의 효율성
로컬 Prefixed 파티션 인덱스와 비교
① 로컬 Prefixed 파티션 인덱스는 계좌번호 조건을 만족하지 않는 거래 데이터까지 모두 스캔
② 로컬 Nonprefixed 파티션 인득스는 각 인덱스 파티션마다 필요한 최소 범위만 스캔.
create table 일별계좌별거래 (
계좌번호 number
, 거래일자 date
, 거래량 number
, 거래금액 number
)
partition by range(거래일자)(
partition p01 values less than(to_date('20090201', 'yyyymmdd'))
, partition p02 values less than(to_date('20090301', 'yyyymmdd'))
, partition p03 values less than(to_date('20090401', 'yyyymmdd'))
, partition p04 values less than(to_date('20090501', 'yyyymmdd'))
, partition p05 values less than(to_date('20090601', 'yyyymmdd'))
, partition p06 values less than(to_date('20090701', 'yyyymmdd'))
, partition p07 values less than(to_date('20090801', 'yyyymmdd'))
, partition p08 values less than(to_date('20090901', 'yyyymmdd'))
, partition p09 values less than(to_date('20091001', 'yyyymmdd'))
, partition p10 values less than(to_date('20091101', 'yyyymmdd'))
, partition p11 values less than(to_date('20091201', 'yyyymmdd'))
, partition p12 values less than(maxvalue)
) ;
declare
l_first_date date;
l_last_day number;
begin
for i in 1..12
loop
l_first_date := to_date('2009' || lpad(i, 2, '0') || '01', 'yyyymmdd');
l_last_day := to_number(to_char(last_day(l_first_date), 'dd'));
insert into 일별계좌별거래
select rownum 계좌번호
, l_first_date + mod(rownum, l_last_day) 거래일자
, round(dbms_random.value(100, 10000)) 거래량
, round(dbms_random.value(10000, 1000000)) 거래금액
from dual
connect by level <= 10000;
end loop;
end;
/
create index local_prefix_index on 일별계좌별거래(거래일자, 계좌번호) local;
create index local_nonprefix_index on 일별계좌별거래(계좌번호, 거래일자) local;
select /*+ index(t local_prefix_index) */ sum(거래량), sum(거래금액)
from 일별계좌별거래 t
where 계좌번호 = 100
and 거래일자 between to_date('20090115', 'yyyymmdd')
and to_date('20091215', 'yyyymmdd')
;
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.000 0 0 0 0
Execute 1 0.000 0.000 0 0 0 0
Fetch 2 0.016 0.023 0 387 0 1
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 4 0.016 0.023 0 387 0 1
Misses in library cache during parse: 0
Optimizer goal: ALL_ROWS
Parsing user: KJWON (ID=64)
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
1 SORT AGGREGATE (cr=387 pr=0 pw=0 time=22846 us)
11 PARTITION RANGE ALL PARTITION: 1 12 (cr=387 pr=0 pw=0 time=16366 us)
11 TABLE ACCESS BY LOCAL INDEX ROWID 일별계좌별거래 PARTITION: 1 12 (cr=387 pr=0 pw=0 time=22704 us)
11 INDEX RANGE SCAN LOCAL_PREFIX_INDEX PARTITION: 1 12 (cr=376 pr=0 pw=0 time=8009 us)(Object ID 52990)
select /*+ index(t local_nonprefix_index) */ sum(거래량), sum(거래금액)
from 일별계좌별거래 t
where 계좌번호 = 100
and 거래일자 between to_date('20090115', 'yyyymmdd')
and to_date('20091215', 'yyyymmdd')
;
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.000 0 0 0 0
Execute 1 0.000 0.000 0 0 0 0
Fetch 2 0.000 0.001 0 35 0 1
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 4 0.000 0.001 0 35 0 1
Misses in library cache during parse: 0
Optimizer goal: ALL_ROWS
Parsing user: KJWON (ID=64)
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
1 SORT AGGREGATE (cr=35 pr=0 pw=0 time=544 us)
11 PARTITION RANGE ALL PARTITION: 1 12 (cr=35 pr=0 pw=0 time=532 us)
11 TABLE ACCESS BY LOCAL INDEX ROWID 일별계좌별거래 PARTITION: 1 12 (cr=35 pr=0 pw=0 time=433 us)
11 INDEX RANGE SCAN LOCAL_NONPREFIX_INDEX PARTITION: 1 12 (cr=24 pr=0 pw=0 time=232 us)(Object ID 53003)
글로벌 Prefixed 파티션 인덱스와 비교
① Prefixed 파티션만 혀용되므로 로컬 Prefixed 파티션과 마찬가지로 인덱스 스캔 효율이 나쁘다.
② 파티션 단위 작업 시 매번 인덱스를 재생성해야 하므로 관리적 부담.
① Unique 파티션 인덱스를 정의할 때는 인덱스 파티션 키가 모두 인덱스 구성 컬럼에 포함돼어야 한다.
② 글로벌 파티션 인덱스는 Prefixed 파티션이어야 한다.
③ 인덱스를 통해 액세스할 데이터량이 아주 많아 빠른 성능을 내기 어렵고, Full Table Scan으로 처리하기에는
너무 많은 양을 읽어야 할 때 주로 파티셔닝을 실시.
④ 파티셔닝은 인덱스 전략 수립과 병행