h1.03.인덱스 파티셔닝
h3.(1) 인덱스 파티션 유형
h3.(2) 로컬 파티션 인덱스
h3.(3) 비파티션 인덱스
h3.(4) 글로벌 파티션 인덱스
alter table ...
split partition ...
update global indexes;
h4.글로벌 해시 파티션 인덱스
h3.(5) Prefixed vs. Nonprefixed
h3.(6) 파티션 인덱스 구성 예시
h4.인덱스 파티셔닝 예제
SQL> create table t ( gubun
, seq, seq_name, seq_cls
, seq2, seq2_name, seq2_cls
)
partition by range(seq) (
partition p1 values less than(100)
, partition p2 values less than(200)
, partition p3 values less than(300)
, partition p4 values less than(maxvalue)
)
as
select 1
, rownum, dbms_random.string('u', 10), 'A'
, rownum, dbms_random.string('l', 10), 'B'
from dual
connect by level <= 400 ;
Table created.
-- seq 컬럼으로 range 파티셔닝한 테이블 생성
--1. 로컬인덱스 생성 시도
SQL> create unique index t_idx1 on t(gubun, seq2) LOCAL ;
create unique index t_idx1 on t(gubun, seq2) LOCAL
*
ERROR at line 1:
ORA-14039: partitioning columns must form a subset of key columns of a UNIQUE index
--에러 원인
--로컬인덱스인데 파티션키가 인덱스 구성에 미포함
--2. 위와 동일한 구성인데 LOCAL을 빼고 실행, 비파티션인덱스 생성시도
SQL> create unique index t_idx1 on t(gubun, seq2) ;
Index created.
--3. Nonprefixed, Prefixed 로컬 인덱스 생성시도
SQL> create unique index t_idx2 on t(gubun, seq) LOCAL ;
Index created.
SQL> create index t_idx3 on t(seq, gubun) LOCAL ;
Index created.
--4. 글로벌 파티션 인덱스 생성 시도
SQL> create index t_idx5 on t(seq_cls, seq) GLOBAL
partition by range(seq) (
partition p1 values less than(100)
, partition p2 values less than(200)
, partition p3 values less than(300)
, partition p4 values less than(maxvalue)
)
;
ERROR at line 2:
ORA-14038: GLOBAL partitioned index must be prefixed
--에러원인
--글로벌 파티션인덱스는 prefixed만 지원함.
SQL> create index t_idx5 on t(seq, seq_cls) GLOBAL
partition by range(seq) (
partition p1 values less than(100)
, partition p2 values less than(200)
, partition p3 values less than(300)
, partition p4 values less than(maxvalue)
) ;
Index created.
--글로벌 Prefixed 인덱스 생성 성공
--그런데, 위 인덱스가 테이블 파티션과 100% 같게 정의하더라도 위 인덱스는 글로벌 파티션인덱스이다.
create index t_idx10 on t(seq, seq_cls) LOCAL ; 와 다르다.
--5. 파티션 정보 조회쿼리
select i.index_name, i.uniqueness, p.locality
, p.alignment, i.partitioned, p.partition_count
from user_indexes i, user_part_indexes p
where i.table_name = 'T'
and p.table_name(+) = i.table_name
and p.index_name(+) = i.index_name
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 개의 행이 선택되었습니다.
h3.(7) 글로벌 파티션 인덱스의 효용성
결론 : NL 조인에서 넓은 범위 조건을 가지고 Inner 테이블 액세스를 위해 자주 사용된다면 비파티션 인덱스가 가장 좋은 선택.
h4.②테이블과 다른 컬럼으로 파티셔닝하는 경우
h3.(8) 로컬 Nonprefixed 파티션 인덱스의 효용성
h4.로컬 Prefixed 파티션 인덱스와 비교
SQL> create table 일별계좌별거래 (
2 계좌번호 number
3 , 거래일자 date
, 거래량 number
4 5 , 거래금액 number
6 )
7 partition by range(거래일자)(
partition p01 values less than(to_date('20090201', 'yyyymmdd'))
8 9 , partition p02 values less than(to_date('20090301', 'yyyymmdd'))
10 , partition p03 values less than(to_date('20090401', 'yyyymmdd'))
11 , partition p04 values less than(to_date('20090501', 'yyyymmdd'))
12 , partition p05 values less than(to_date('20090601', 'yyyymmdd'))
13 , partition p06 values less than(to_date('20090701', 'yyyymmdd'))
14 , partition p07 values less than(to_date('20090801', 'yyyymmdd'))
15 , partition p08 values less than(to_date('20090901', 'yyyymmdd'))
16 , partition p09 values less than(to_date('20091001', 'yyyymmdd'))
17 , partition p10 values less than(to_date('20091101', 'yyyymmdd'))
18 , partition p11 values less than(to_date('20091201', 'yyyymmdd'))
19 , partition p12 values less than(maxvalue)
20 ) ;
Table created.
SQL> declare
2 l_first_date date;
3 l_last_day number;
begin
4 5 for i in 1..12
6 loop
l_first_date := to_date('2009' || lpad(i, 2, '0') || '01', 'yyyymmdd');
7 8 l_last_day := to_number(to_char(last_day(l_first_date), 'dd'));
9 insert into 일별계좌별거래
10 select rownum 계좌번호
11 , l_first_date + mod(rownum, l_last_day) 거래일자
12 , round(dbms_random.value(100, 10000)) 거래량
13 , round(dbms_random.value(10000, 1000000)) 거래금액
14 from dual
connect by level <= 10000;
15 16 end loop;
17 end;
18 /
PL/SQL procedure successfully completed.
SQL> create index local_prefix_index on 일별계좌별거래(거래일자, 계좌번호) local;
Index created.
SQL> create index local_nonprefix_index on 일별계좌별거래(계좌번호, 거래일자) local;
Index created.
SQL> select /*+ index(t local_prefix_index) */ sum(거래량), sum(거래금액)
from 일별계좌별거래 t
where 계좌번호 = 100
and 거래일자 between to_date('20090115', 'yyyymmdd')
and to_date('20091215', 'yyyymmdd')
;
--------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 48 | 485 (1)| 00:00:06 | | |
| 1 | SORT AGGREGATE | | 1 | 48 | | | | |
| 2 | PARTITION RANGE ALL | | 21 | 1008 | 485 (1)| 00:00:06 | 1 | 12 |
| 3 | TABLE ACCESS BY LOCAL INDEX ROWID| 일별계좌별거래 | 21 | 1008 | 485 (1)| 00:00:06 | 1 | 12 |
|* 4 | INDEX RANGE SCAN | LOCAL_PREFIX_INDEX | 483 | | 436 (1)| 00:00:06 | 1 | 12 |
--------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("거래일자">=TO_DATE(' 2009-01-15 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "계좌번호"=100 AND
"거래일자"<=TO_DATE(' 2009-12-15 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
filter("계좌번호"=100)
--로컬 Prefixed 파티션 인덱스는 계좌번호 조건을 만족하지 않는 거래 데이터까지 모두 스캔
SQL> select /*+ index(t local_nonprefix_index) */ sum(거래량), sum(거래금액)
from 일별계좌별거래 t
where 계좌번호 = 100
and 거래일자 between to_date('20090115', 'yyyymmdd')
and to_date('20091215', 'yyyymmdd')
;
-----------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 48 | 14 (0)| 00:00:01 | | |
| 1 | SORT AGGREGATE | | 1 | 48 | | | | |
| 2 | PARTITION RANGE ALL | | 21 | 1008 | 14 (0)| 00:00:01 | 1 | 12 |
| 3 | TABLE ACCESS BY LOCAL INDEX ROWID| 일별계좌별거래 | 21 | 1008 | 14 (0)| 00:00:01 | 1 | 12 |
|* 4 | INDEX RANGE SCAN | LOCAL_NONPREFIX_INDEX | 21 | | 13 (0)| 00:00:01 | 1 | 12 |
-----------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("계좌번호"=100 AND "거래일자">=TO_DATE(' 2009-01-15 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "거래일자"<=TO_DATE('
2009-12-15 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
--로컬 Nonprefixed 파티션 인덱스는 각 인덱스 파티션마다 필요한 최소 범위만 스캔.
h4.글로벌 Prefixed 파티션 인덱스와 비교
h4.비파티션 인덱스와 비교
h4.일 단위 파티셔닝
<참고쿼리문>
1. select 계좌번호, count(*)
from 일별계좌별집계
where 계좌번호 = :acnt_no
h3.(9) 액세스 효율을 고려한 인덱스 파티셔닝 선택 기준
h4.DW성 애플리케이션 환경
h4.OLTP성 애플리케이션 환경
h3.(10) 인덱스 파티셔닝 제약을 고려한 데이터베이스 설계