by 지현명 [PostgreSQL 노하우/팁/자료] PostgreSQL Partition [2018.03.06 09:52:59]
--https://www.postgresql.org/docs/10/static/ddl-partitioning.html
-------------------------------------------------------------------------------
--RANGE 파티션
--------------------------------------------------------------------------------
CREATE TABLE measurement (
city_id int not null,
logdate date not null,
peaktemp int,
unitsales int
) PARTITION BY RANGE (logdate);
--오류: "measurement" 파티션된 테이블 대상으로 인덱스를 만들 수 없음
CREATE INDEX ON measurement (logdate);
--메인 부모 테이블에 인덱스를 만들 수 없다.
CREATE TABLE measurement_y2006m02 PARTITION OF measurement
FOR VALUES FROM ('2006-02-01') TO ( '2006-03-01');
--CHECK ( logdate >= DATE '2008-02-01' AND logdate < DATE '2008-03-01' );
CREATE TABLE measurement_y2006m03 PARTITION OF measurement
FOR VALUES FROM ('2006-03-01') TO ('2006-04-01');
CREATE INDEX ON measurement_y2006m02 (logdate);
CREATE INDEX ON measurement_y2006m03 (logdate);
--파티션 테이블을 메인 부모 테이블에서 분리 시키려면 DETACH
--DETACH 하면 조건절이 삭제 되면서 일반 테이블로 풀립니다.
--pgAdmin4에서도 일반 테이블로 보여집니다.
ALTER TABLE measurement DETACH PARTITION measurement_y2006m03;
--이거 때문에 다시 ATTACH하려면 조건절 다시 입력해야 합니다.
ALTER TABLE measurement ATTACH PARTITION measurement_y2006m03
FOR VALUES FROM ('2006-03-01') TO ('2006-04-01'); --이렇게 다시ATTACH하려면 조건을 입력해야 합니다.
--DETACH하더라도 조건절을 유지 할줄 알았는데 그래서 ATTACH 할때 헛갈렸습니다. 조건절 다시 안쓰니까 에러나서...
--풀릴때 CHECK 라도 유지하고 다시 ATTACH할때 CHECK를 자동으로 삭제하면 될거 같은데..이거 메뉴얼 보니 수동으로 해야 하네요...
insert into measurement values (1, '2006-02-01', 1, 1),(2, '2006-03-01', 2, 2);
insert into measurement values (3, '2006-03-01', 1, 1);
select * from measurement;
--show constraint_exclusion;
analyze measurement_y2006m02;
analyze measurement_y2006m03;
select * from measurement_y2006m03
--이렇게 하면 파티션 Pruning이 안됩니다.
--파티션 Pruning이 되게 하려면 파티션 조건하고 동일한 데이터 type으로 해야 합니다.
explain (costs false)
select * from measurement
where logdate = to_date('20060301', 'YYYYMMDD')
--where logdate = DATE '2006-03-01'
explain (costs false)
select * from measurement
where logdate in (DATE '2006-02-01')
------------------------------------------------------------
--파티션 테이블의 통계정보 갱신
------------------------------------------------------------
VACUUM or analyze 은 파티션 각 테이블 별로 해야함.
--파티션 range값을 다른 파티션 테이블로 변경할 경우 에러 발생
select * from measurement
where city_id = 1;
--에러발생
--파티션 키 값을 update하면 에러발생합니다. ms-sql과 다른점입니다.
--트리거로 이동하는 함수 작성해서 연결해 줘야 합니다.
update measurement
set
logdate = '2006-03-01'
where city_id = 1;
------------------------------------------------------------
--PostgreSQL 파티션 Pruning
/*
* NL 조인으로 수행되면 추가 조건 없이도 파티션 Pruning이 수행된다.
* Hash 조인으로 수행되면 추가 조건을 반드시 입력해야 한다.
* 따라서, 쿼리 작성 후에 Explain 결과 확인 및 추가 조건을 입력할 필요가 있다.
*/
------------------------------------------------------------
create table p1 (
c1 integer,
logdate date,
dummy char(10)
) partition by range (logdate);
create table p2 (
c1 integer,
logdate date,
amount integer,
dummy char(10)
) partition by range (logdate);
create table p1_y201701 partition of p1 for values from ('2017-01-01') to ('2017-02-01');
create table p1_y201702 partition of p1 for values from ('2017-02-01') to ('2017-03-01');
create table p1_y201703 partition of p1 for values from ('2017-03-01') to ('2017-04-01');
create table p1_y201704 partition of p1 for values from ('2017-04-01') to ('2017-05-01');
create table p2_y201701 partition of p2 for values from ('2017-01-01') to ('2017-02-01');
create table p2_y201702 partition of p2 for values from ('2017-02-01') to ('2017-03-01');
create table p2_y201703 partition of p2 for values from ('2017-03-01') to ('2017-04-01');
create table p2_y201704 partition of p2 for values from ('2017-04-01') to ('2017-05-01');
set enable_nestloop=on;
set enable_mergejoin=off;
set enable_hashjoin=off;
explain (costs false)
select count(*)
from p1 a inner join p2 b using (logdate)
where 1=1
and a.c1 = b.c1
and a.logdate between DATE '2017-01-15' and DATE '2017-01-31'
and b.logdate between DATE '2017-01-15' and DATE '2017-01-31'
;
explain (analyse, buffers)
select count(*)
from p1 a inner join p2 b using (logdate)
where 1=1
--a.logdate = b.logdate
and a.c1 = b.c1
and a.logdate between DATE '2017-01-15' and DATE '2017-01-31'
and b.logdate between DATE '2017-01-15' and DATE '2017-01-31'
;
-------------------------------------------------------------------------------
--List 파티션
--------------------------------------------------------------------------------
create table list_p1
(
c1 integer,
code integer,
dummy char(100)
) PARTITION BY LIST (c1);
CREATE TABLE list_p1_code1
PARTITION OF list_p1 for values in(1);
CREATE TABLE list_p1_code2
PARTITION OF list_p1 for values in(2);
insert into list_p1 values(3, 1, 'test')
select * from list_p1_code2