본문 바로가기

sql_tuning

5. 파티셔닝

728x90
반응형

파티션 테이블 생성 관리

*목차

1. 테이블 파티셔닝

2. 파티션 pruning

3. 인덱스 파티셔닝

 

파티셔닝이란?

 파티셔닝은 테이블 또는 인덱스를 파티션 단위로 나누어서

저장하는 것을 말한다.

 테이블을 파티셔닝하면 하나의 테이블일지라도

파티션 키에 따라 물리적으로 별도의 세그먼트에 데이터가

저장된다.

 

 

그림의 옷장서랍을 빗대어 설명하면,

, 여름, 가을, 겨울 옷을 따로 다른 서랍(partition) 저장해두면

검색속도가 빨라진다.

해당 파티션만 검색하면 되기 때문에 성능이 좋아진다.

 

파티셔닝을 사용하는 것인가?

            빠르게 data 검색하기 위하여.

 

 

파티셔닝의 장점

 1. 관리적 측면: 보관주기가 지난 data 들을 별도로 백업하고

                     지우는 일이 아주 쉬워진다.

 

 2. 성능적 측면: 파티셔닝 하지 않는 테이블들이 대용량일

                    인덱스를 이용해서 data 검색하더라도

                    data 양이 많아서 인덱스를 이용해

                    건건이 테이블을 엑세스 하는 방식은

                    일정량이 넘는 순간 full table scan 보다

                     못한 결과가 나온다.

                    그렇다고 full table scan 해도 부담스럽다면

                    바로 파티션을 나누면

                    full table scan 하더라도 일부 파티션 세그먼트만

                    읽고 멈출 있다.

 

 

파티션 생성

문제82. 아래의 수동 파티셔닝을 파티션 뷰로 구현하시오

 

demobld

 

1. 파티션 뷰를 정의할 사용할 base 테이블을 만든다.

create table p1

as

select * from emp

where deptno = 10;

 

create table p2

as

select * from emp

where deptno = 20;

 

create table p3

as

select * from emp

where deptno = 30;

 

 

2. 체크 제약을 반드시 설정해야

alter table p1

add constraint c_deptno_10 check(deptno < 20);

 

alter table p2

add constraint c_deptno_20 check(deptno >= 20 and deptno < 30);

 

 

alter table p3

add constraint c_deptno_30 check(deptno >=  30 and deptno < 40);

 

 

3. 인덱스를 생성한다

create index p1_empno_idx on p1(empno);

 

create index p2_empno_idx on p2(empno);

 

create index p3_empno_idx on p3(empno);

 

 

4. 3개의 테이블에 대하여 분석작업을 한다

analyze table p1 compute statistics;

 

analyze table p2 compute statistics;

 

analyze table p3 compute statistics;

 

 

 

문제83. p2 테이블에 아래의 data 입력하시오

empno : 3829

ename: jack

sal        : 4000

deptno: 30

 

insert into p2(empno, ename, sal, deptno)

values(3829, 'jack', 4000, 30);

 

 

에러

 

※설명: p1 테이블에는 부서번호 10번만 입력할 있고

         p2 테이블에는 부서번호 20번만 입력할 있고

         p3 테이블에는 부서번호 30번만 입력할 있다.

       

 

 

문제84. 위에서 준비된 3개의 테이블(segment) 이용해서

 파티션 view 생성하시오

 

create or replace view emp_partition

 as

 select * from p1

union all

 select * from p2

union all

 select * from p3;

 

select * from emp_partition;

 

 

 

 

문제85. 부서번호 20번인 사원들의 모든 컬럼을 출력하는

아래의 2개의 SQL 성능을 비교해보시오

(BLOCK 갯수)

 

SELECT *

FROM EMP_PARTITION

WHERE deptno = 20;

 

 

 

 

 

SELECT *

FROM EMP

WHERE deptno = 20;

 

 

 

 

작은 테이블도 이렇게 블럭갯수 차이가 나는데

대용량 처리할 때는 엄청난 시간단축을 도와준다.

(개념의 이해를 위해 하셨다고 .

  현업에서는 partition view 안쓴다고 )

 

 

 

파티션 테이블 생성

 

86. 이번에는 파티션 말고

실제로 파티션 테이블을 생성하시오

(pdborcl 에서만 됩니다!!!!!!!!!)

 

create table emp_partition2

partition by range(deptno)

 (

   partition p1 values less than (20),

   partition p2 values less than (30),

   partition p3 values less than (40)

  )

 as

 select * from emp;

 

select * from emp_partition2;

 

 

 

 

이제 아래 2개의 테이블의 블럭수를 비교해보자

select * from emp_partition2

where deptno = 20;

 

select * from emp

 where deptno = 20;

 

emp_partition2 블럭수가 적다.

 

 

 

문제87. 우리반 테이블을 12c database 구현하시오.

 

  12c database(orcl) --------------> 11g database(xe)

            

create public database link link_11g

 connect to scott

 identified by tiger

 using 'localhost:1521/xe';

 

select * from tab@link_11g;

 

create table emp2

 as

 select * from emp2@link_11g;

 

 

 

문제88. 우리반 테이블로 range 파티션 테이블을 생성하시오

 

파티션 테이블명: emp2_partition

파티션 컬럼  : age

파티션 나누는 기준: p1 (26 이하)

                          p2 (28 이하)

                          p3 (30 이하)

                          p4 (45 이하)

 

create table emp2_partition

partition by range(age)

 (

   partition p1 values less than (27),

   partition p2 values less than (29),

   partition p3 values less than (31),

   partition p4 values less than (46)

 )

 as

 select * from emp2;

 

select * from emp2_partition;

 

 

 

문제89. 나이가 26살인 학생들의 이름, 나이를 출력하는데

 

select ename, age

from emp2_partition

where age = 26;

 

select ename, age

from emp2

where age=26;

 

 

※파티션 테이블의 효과를 보려면

   파티션 마다 data 골고루 분포 되어야 한다.

 

*emp2_partition 테이블에 대해서 분석 작업 수행

 

exec dbms_stats.gather_table_stats('SCOTT', 'EMP2_PARTITION');

 

 select table_name, partition_name, num_rows

 from user_tab_partitions

 where table_name = 'EMP2_PARTITION' ;

 

 

 

화면 캡처: 2018-11-13 오전 11:19

 

이러면 잘못 만든 파티션이다.

데이터가 골고루 분포되어 있어야 한다.

 

 

파티션의 종류

1. range 파티션 ----> 날짜 컬럼, 숫자 컬럼 기준으로 나눈

                              파티션 테이블(범위를 지정할 있는 컬럼)

 : sk 텔레콤의 요금 테이블의 월별 파티션

      또는 emp deptno, emp2 age

 

2. hash 파티션 -----> 해시함수를 이용해서 오라클이 알아서 data

                            정해진 파티션 갯수만큼 골고루 분배하는

                            파티션

  장점: 파티션 테이블을 생성하기 편하다.

  단점: 어느 데이터가 어느 파티션에 들어가 있는지

           알기 어려움.

                         괜찮다. 알아서 정리 되있으니까.

                         현업에서 많이 사용한다.

 

3. list 파티션---------> 사용자에 의해 미리 정해진 그룹핑 기준에 따라

                        데이터를 분할하는 파티션(range 비슷)

   : 우리반 테이블을 통신사별로 파티셔닝 하고 싶다.

       sk, kt, lg

 

4. 복합 파티션

   range - hash 파티션

   range - list   파티션

   range - range파티션

   list    -  hash 파티션

   list    -  list   파티션

   list    -  range파티션

 

 

hash 파티션 생성 방법

 

create table emp195

 partition by hash(deptno) partitions 3

as

  select * from emp;

 

골고루 분배됬나 확인해보기

exec dbms_stats.gather_table_stats('SCOTT', 'EMP195');

 

 select table_name, partition_name, num_rows

 from user_tab_partitions

 where table_name = 'EMP195' ;

 

hash 우리가 옷장서랍 갯수만 정해주면

옵티마이져가 알아서 넣어준다.

 

 

 

 

문제90. 우리반 테이블을 해시 파티션으로 생성하시오

 (파티션 테이블 이름: emp2_hash_partition)

파티션 key = age

 

create table emp2_hash_partition

partition by hash(age) partitions 4

as

 select * from emp2;

 

exec dbms_stats.gather_table_stats('SCOTT', 'EMP2_HASH_PARTITION');

 

select table_name, partition_name, num_rows

 from user_tab_partitions

 where table_name = 'EMP2_HASH_PARTITION';

 

 

문제91. 사원 테이블의 부서번호로 list 파티션 생성하시오

 

create table emp_list_partition

 partition by list(deptno)

 (partition p1 values('10'),

  partition p2 values('20'),

  partition p3 values('30') )

 as

 select * from emp;

 

exec dbms_stats.gather_table_stats('SCOTT', 'EMP_LIST_PARTITION');

 

select table_name, partition_name, num_rows

 from user_tab_partitions

 where table_name = 'EMP_LIST_PARTITION';

 

 

문제92.(점심시간 문제)

우리반 테이블을 통신사별로 나눠서 리스트 파티션 테이블

생성하시오

update emp2

 set telecom = 'sk'

 where telecom = 'SK';

 

create table emp2_list_partition

partition by list (telecom)

(

 partition p1 values('sk'),

 partition p2 values('kt'),

 partition p3 values('lg')

 )

 as

 select * from emp2;

 

exec dbms_stats.gather_table_stats ('SCOTT', 'EMP2_LIST_PARTITION');

 

select table_name, partition_name, num_rows

 from user_tab_partitions

 where table_name = 'EMP2_LIST_PARTITION';

 

 

 

 

 

 

파티션 테이블 생성 관리

*목차

1. 테이블 파티셔닝

2. 파티션 pruning

3. 인덱스 파티셔닝

 

 

파티션 pruning

 Prune ?    쓸데없는 가지를 치다

                      불필요한 부분을 제거하다

                       (= partition range single)

 

 SQL 실행하는 시점에서 SQL 조건절을 분석해서

읽지 않아도 되는 파티션 세그먼트를 엑세스 대상에서

제외시키는 기능

 

*파티션 프루닝이 되고 있는 실행계획

 

select *

from emp_partition2

where deptno =20;

 

 

partition range single ->

         파티션 프루닝이 되고있다

     옷장의 해당 서랍만 열었다

 

 

문제93. 점심시간 문제로 만들었던

통신사별로 구분한 파티션 테이블의 쿼리문을

작성해서

파티션 프루닝을 하는지 확인하시오.

 

select *

from emp2_list_partition

where telecom = 'sk';

 

**where 있어야지( 조건있어야지) single(=prune) 보는지

  있다. (조건없으면 그냥 풀탐)

 

 

*실행계획 보는 방법 2가지

 1. 예상 실행계획 보는 방법 -> sql gate 에서 F7 누르면 된다.

 2. 실제 실행계획 보는 방법 -> 실제로 실행을 하면서 실행할

                                          수행했던 계획 확인

 

select /*+ gather_plan_statistics */ *

from emp_partition2

where deptno = 20;

>>>>>>>실제실행계획 보는거

 

select *

from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST +alias +outline +predicate'));

                     

 

 

파티션 프루닝이 안되는 경우

1. where 조건 컬럼을 가공했을

2. 등치조건이나 in 조건이 아닐 (hash 파티션일때)

 

 

select *

 from emp_partition2

 where trim(deptno) = 20; <<<<whrere 가공

*******trim 없으면 single(prune) 탑니다.

 

select /*+ gather_plan_statistics */ *

from emp_partition2

where trim(deptno) = 20;

>>>>>>>실제실행계획 보는거

 

all 했다.

 

 

 

select *

 from emp195   <<<<<<<<<<<<hash파티션 걸어놓은 테이블

 where deptno like '2%';

 

 

 

hash all!!!!!!!

<등치조건이나 in 조건이 아닐 (hash 파티션일때)>

 

 

 

 

 

파티션 와이즈 조인 wise join

                  " 파티션 끼리 조인 하는   "

 

 

                       10         20         30        40

emp_partition                                

                                                      ↓ →파티션끼리 조인

dept_partition                                

 

 

 

 

*파티션 와이즈 조인이 아닌 경우

 

emp    10    20    10    20    30    10    20    20    30    10    20    30   ... ...

                                              → →

           

dept   10    20    30    40

 

 

문제94. emp_partition 파티션 테이블과

          dept_partition 파티션 테이블을

          deptno 파티션 키로 생성하시오 (레인지 파티션)

 

drop view emp_partition;

drop table emp_partition;

 

create table emp_partition

 partition by range(deptno)

(

 partition p1 values less than (20),

 partition p2 values less than (30),

 partition p3 values less than (40),

 partition p4 values less than (50)

 )

 as select * from emp;

 

 

create table dept_partition

partition by range(deptno)

( partition p1 values less than (20),

 partition p2 values less than (30),

 partition p3 values less than (40),

 partition p4 values less than (50)

 )

 as select * from dept;

 

 

 select * from emp_partition;

 select * from dept_partition;

 

 

문제95. emp_partition dept_partition

          조인해서 이름, 부서위치, 부서번호를 출력하고

          실행계획을 확인하시오

 

select e.ename, d.loc, e.deptno

 from emp_partition e, dept_partition d

where e.deptno = d.deptno;

 

 

 

 

 

문제96. 위의 조인문을 해시조인으로 유도해서

 파티션 와이즈 조인 되게 하시오.

select /*+ leading (d e) use_hash(e)

            full(d)     full(e)

             parellel(e 2)  parallel(d 2)        <<해쉬 병렬구조 중요

             pq_distribute(e.none.none) */

 e.ename, d.loc, e.deptno

 from emp_partition e, dept_partition d

where e.deptno = d.deptno;

 

 

*이렇게 실행계획이 나와야

 파티션 와이즈 조인 이다.

 

* 빠르게 >>>>> parallel

*와이즈 조인유도: pq_distribute(e.none.none)

 ******* 찍는거 주의*****************

 

조인하려는 테이블이 파티션 테이블인데

   실행계획 돌렸는데 파티션 와이즈 조인을 한다면

pq_distribute(e.none.none) 힌트 사용해야 한다.

PQ_DISTRIBUTE( Inner, none, none )

  • Full-Partition Wise 조인으로 유도할 때 사용한다.

연히,

양쪽 테이블 모두 조인 컬럼에 대해 같은 기준으로

파티셔닝( equi-partitioning ) 돼 있을 때만 작동한다.

 

 

 

작업은 2 테이블에 미리 파티셔닝이 걸려있을 때다.

미리 파티셔닝이 걸려 있는 상황에서 있는

힌트가 있다

파티션 테이블이 아닌 경우 (동적 파티셔닝)

PQ_DISTRIBUTE( Inner, hash, hash )

  • 조인 키 컬럼을 해시 함수에 적용하고 거기서 반환된 값을 기준으로

양쪽 테이블을 동적으로 파티셔닝 하라는 뜻이다.

 

 

         ------------------------------->

  조인:  outer table   :   inner table

             (dept)           (emp)

           파티션x          파티션x

          big table        big table

 

 힌트: pq_distribute(emp.hash.hash)

 

 

 

테이블을 파티셔닝 하고 full partition wise 조인해라

*근데 좋지 못함. 메모리 잡아먹으면서 내리는 명령이라서.

 

 

select /*+ leading (d e) use_hash(e)

            full(d)     full(e)

             parellel(e 2)  parallel(d 2)

             pq_distribute(e.hash.hash) */

 e.ename, d.loc, e.deptno

 from emp_partition e, dept_partition d

where e.deptno = d.deptno;

 

 

 

 

문제97. 우리반테이블(emp2) telecom_price 테이블을 조인해서

 이름, 나이, 텔레콤, month_price 출력하는데

 파티션 와이즈 조인 되게 하시오

 

**지금 12c 니까 dblink telecom_price 갖고 와야함

 

create table telecom_price

 as

 select * from telecom_price@link_11g;

 

(파티셔닝이 걸려있다는 전제니까

 pq_distributes(e.hash.hash) )

 

select /*+ leading( t e) use_hash(e) full(t) full(e)

                 parallel(t 2)  parallel(e 2)

                 pq_distribute(e.hash.hash) */

         e.ename, e.age, e.telecom, t.month_price

  from emp2 e, telecom_price t

where e.telecom = t.telecom_name;

 

 

 

 

목차

 1. 테이블 파티셔닝

 2. 파티션 pruning

 3. 인덱스 파티셔닝

 

3. 인덱스 파티셔닝

 인덱스의 크기가 너무 커서 인덱스를 파티션해서 성능을 높이겠다.

 

*인덱스 파티션의 종류

 

1. 로컬 파티션 인덱스

파티션 테이블의 파티션에 각각 로컬 인덱스로 구성된 구조의 인덱스

** 서랍장마다 인덱스가 별개로 있는 .

***가장 많이 사용함. 단점은 저장공간을 많이 차지함.

① 각 인덱스 파티션이 테이블 파티션과 1:1 대응 관계를 가지며, 테이블 파티션 속성을 그대로 상속받는다.

② 파티션 키를 사용자가 따로 정의하지 않아도 오라클이 자동으로 관리

③ 테이블 파티션과 1:1 관계가 되도록 사용자가 수동으로 인덱스 파티션을 구성하더라도 이를 로컬 파티션 인덱스라고 부르지 않는다.

테이블이 결합 파티셔닝 돼 있다면 인덱스도 같은 단위로 파티셔닝

테이블 파티션 구성에 변경이 생기더라도 인덱스를 재생성할 필요가 없다.

 

 

 

 

 

2. 파티션 인덱스 (=글로벌 파티션 인덱스)

테이블 파티션 되어져 있는데 인덱스 파티셔닝 되지 않은 인덱스

**저장공간을 쓴다.

 

 

① 파티셔닝하지 않은 인덱스

② 1:M 관계 [1:M = 인덱스:여러테이블]

③ 하나의 인덱스 세그먼트가 여러 테이블 파티션 세그먼트와 관계

④기준 테이블의 파티션 구성에 변경(drop, exchange, split등)이

   생길 때마다 인덱스가 unusable 상태로 바뀌고 그때마다 

   인덱스를 재생성REBUILD해야 한다.

   [ '글로벌 비파티션 인덱스'라 부르기도 한다. ]

 

 

 

 

3. 글로벌 파티션 인덱스

테이블도 파티션 되어져 있고 인덱스도 파티션 되어있는데

 테이블 파티션과 인덱스 파티션과의 관계가 서로 독립적 구조

되어있는 인덱스

① 테이블 파티션과 독립적인 구성을 갖도록 파티셔닝하는 것

② 테이블은 파티셔닝돼 있지 않을 수도 있다.

③ 기준 테이블의 파티션 구성에 변경(drop, exchange, split등)이 생길 때마다 인덱스가 unusable 상태로 바뀌고 그때마다 

인덱스를 재생성해야 한다. (비파티션 인덱스일 때도 동일)

④ 9i(오라클버젼)부터 update global indexes 옵션을 주면

   파티션 DDL 작업에 의해 영향을 받는 인덱스 레코드를

   자동으로 갱신해 준다. (unusable 상태로 빠지지 않는다)

 

 

 

 

테이블 파티션과의 관계

① "오라클이 자동으로 관리해 주는 1:1 관계"가 아닌

   파티션 인덱스는 모두 글로벌 파티션 인덱스

② 하나의 인덱스 파티션이 여러 테이블 파티션과 관계를 갖고,

   반대로 하나의 테이블 파티션이 여러 인덱스 파티션과 관계를 갖는다.

로컬 파티션 인덱스처럼 테이블과 1:1 관계가 되도록 수동으로 구성하더라도      

   글로벌 파티션과 마찬가지로 기준 테이블 구성에 변경이 

    발생할 때마다 인덱스를 재생성해야 한다. 

   (그럼 인덱스 변경 마다 재생성 해야 하네?)

인덱스를 테이블 파티션

 다른 키 컬럼으로

 글로벌 파티셔닝 (테이블은 주문일자, 인덱스는 배송일자) 할 수도 있는데,

  이때는 테이블 파티션과 인덱스 파티션 간에는 항상 M:M 관계가 형성.

 

 

문제98. emp_partition 테이블의 deptno

로컬 파티션 인덱스 생성하시오

 

create index emp_partition_local

on emp_partition(deptno) local;  <<이렇게 뒤에 local 붙여주면 된다.

 

select bytes, blocks

 from user_segments

 where segment_name = 'EMP_PARTITION_LOCAL';

 

 

 

 

*비파티션 인덱스

 drop index emp_partition_local;

 

create index emp_partition_index

 on emp_partition(deptno);  <<<뒤에 local 빼면 된다.

  (local 빼면 비파티션 인덱스)

 

 

로컬 파티션 인덱스 비파티션 인덱스 장단점

-로컬 파티션 인덱스 :  장점 : 관리가 쉽다, 검색 성능이 좋다.

                             단점 : 공간을 많이 사용한다.

 

-비파티션 인덱스 : 장점 : 공간을 적게 사용한다.

                         단점 :  관리가 불편하다.

*어떤점이 관리가 불편한가?

 비파티션 인덱스에 관련된 파티션 테이블을 drop 했을

 비파티션 인덱스가 invalid 되어서 인덱스를 rebuild 해줘야한다.

 

alter table emp_partition

 drop partition p1;

 

select index_name, status

 from user_indexes

 where index_name = 'EMP_PARTITION_INDEX';

 

 

 

unusable 되면 쓴다.

비파티션 인덱스는

파티션과 인덱스가 따로라서

인덱스가 안날라가고 unusable 남아있다.

인덱스를 리빌드 해줘야 한다.

 

시신확인

select /*+ index(e emp_partition_index) */

           ename, sal

 from emp_partition e

 where deptno  = 10;

 

 

 

 

alter index emp_partition_index rebuild;

 

select index_name, status

 from user_indexes

 where index_name = 'EMP_PARTITION_INDEX';

 

select /*+ index(e emp_partition_index) */

           ename, sal

 from emp_partition e

 where deptno  = 20;

***** 20,.............?????????????????

 

 

 

 

로컬 파티션 인덱스 비파티션 인덱스 장단점

-로컬 파티션 인덱스 :  장점 : 관리가 쉽다, 검색 성능이 좋다.

                             단점 : 공간을 많이 사용한다.

 

-비파티션 인덱스 : 장점 : 공간을 적게 사용한다.

                         단점 :  관리가 불편하다.

*어떤점이 불편한가?

 비파티션 인덱스에 관련된 파티션 테이블을 drop 했을

 비파티션 인덱스가 invalid 되어서 인덱스를 rebuild 해줘야한다.

 

*로컬 파티션 인덱스

 1. prefixed  파티션 인덱스: deptno + job(결합컬럼 인덱스)

                                       

                                     파티션 컬럼

                            **파티션 키가 선두에 있음

 

drop index emp_partition_index;

 

create index emp_partition_index

 on emp_partition(deptno, job)  local;

                                        

                            결합컬럼 인덱스

 

글로벌 파티션 인덱스는 Prefixed 파티션만 지원

 

 

 

 2. non prefixed 파티션 인덱스:  job +  deptno

                                                      

                                                  파티션 컬럼

                             **파티션 키가 뒤에 있음

 

 drop index emp_partition_index;

 

create index emp_partition_index

 on emp_partition(job, deptno) local;

 

테이블은 deptno 기준으로 파티션 되어있는데

sql where  절에 주로 job 검색한다고 하면

non prefixed 파티션 인덱스가 필요하다.

 

 

 

728x90
반응형

'sql_tuning' 카테고리의 다른 글

7. 기타 튜닝 방법들  (0) 2019.04.02
6. 병렬처리  (0) 2019.04.02
4. 서브쿼리 튜닝  (0) 2019.04.02
3. 조인 튜닝  (0) 2019.04.02
2-1. 인덱스 엑세스 방법  (0) 2019.04.02