postgres에서 기존 테이블을 파티션하는 방법은 무엇입니까?


19

날짜 범위별로 1M + 행으로 테이블을 분할하고 싶습니다. 가동 중지 시간이 많이 걸리거나 데이터 손실 위험이없는 일반적인 방법은 무엇입니까? 다음은 내가 고려하고있는 전략이지만 제안 사항에 개방적입니다.

  1. 기존 테이블이 마스터이고 하위 테이블이 상속됩니다. 시간이 지남에 따라 데이터를 마스터에서 하위로 이동하지만 일부 데이터는 마스터 테이블에 있고 일부는 하위에 있습니다.

  2. 새 마스터 및 하위 테이블을 작성하십시오. 자식 테이블의 기존 테이블에 데이터 복사본을 만듭니다 (데이터는 두 곳에 상주합니다). 하위 테이블에 최신 데이터가 있으면 새 마스터 테이블을 가리 키도록 계속해서 모든 삽입을 변경하고 기존 테이블을 삭제하십시오.


1
여기 내 아이디어 : 테이블에 날짜 시간 열이있는 경우-> 새 마스터 + 새 자식 만들기-> 새 데이터를 NEW + OLD에 삽입하십시오 (예 : datetime = 2015-07-06 00:00:00)-> OLD에서 NEW 기본으로 복사 시간 열에 (여기서 : datetime <2015-07-06 00:00:00)-> 테이블 이름 바꾸기-> 삽입을 NEW로 변경-> 마스터에서 삽입 / 업데이트를위한 "파티션 트리거"작성 (새 데이터 삽입 / 업데이트- > 자식으로 이동하면 새 데이터가 자식에 삽입됩니다)-> master 업데이트, 트리거는 데이터를 자식으로 이동합니다.
Luan Huynh

@Innnh, 두 번째 옵션을 제안하지만 데이터가 복사되면 이전 테이블을 삭제하고 새 테이블의 이름을 이전 테이블과 동일한 이름으로 바꿉니다. 맞습니까?
Evan Appleby

새 테이블의 이름을 이전 테이블로 바꾸지 만 새 플로우 파티션 테이블이 완전히 확인 될 때까지 이전 테이블을 유지해야합니다.
Luan Huynh

2
몇 백만 행에 대해서는 실제로 파티셔닝이 필요하다고 생각하지 않습니다. 왜 필요하다고 생각하십니까? 어떤 문제를 해결하려고합니까?
a_horse_with_no_name

1
@EvanAppleby DELETE FROM ONLY master_table가 해결책입니다.
dezso

답변:


21

# 1은 활성화 된 프로덕션 환경에있는 동안 마스터에서 자식으로 데이터를 복사해야하므로 개인적으로 # 2를 사용했습니다 (새 마스터 생성). 이렇게하면 원래 테이블이 활발하게 사용되는 동안 원본 테이블이 중단되는 것을 방지하고 문제가있는 경우 문제없이 새 마스터를 쉽게 삭제하고 원본 테이블을 계속 사용할 수 있습니다. 이를 수행하는 단계는 다음과 같습니다.

  1. 새 마스터 테이블을 작성하십시오.

    CREATE TABLE new_master (
        id          serial,
        counter     integer,
        dt_created  DATE DEFAULT CURRENT_DATE NOT NULL
    );
  2. 마스터로부터 상속받은 자식을 만듭니다.

    CREATE TABLE child_2014 (
        CONSTRAINT pk_2014 PRIMARY KEY (id),
        CONSTRAINT ck_2014 CHECK ( dt_created < DATE '2015-01-01' )
    ) INHERITS (new_master);
    CREATE INDEX idx_2014 ON child_2014 (dt_created);
    
    CREATE TABLE child_2015 (
        CONSTRAINT pk_2015 PRIMARY KEY (id),
        CONSTRAINT ck_2015 CHECK ( dt_created >= DATE '2015-01-01' AND dt_created < DATE '2016-01-01' )
    ) INHERITS (new_master);
    CREATE INDEX idx_2015 ON child_2015 (dt_created);
    
    ...
  3. 모든 히스토리 데이터를 새 마스터 테이블로 복사

    INSERT INTO child_2014 (id,counter,dt_created)
    SELECT id,counter,dt_created
    from old_master
    where dt_created < '01/01/2015'::date;
  4. 프로덕션 데이터베이스에 대한 새로운 삽입 / 업데이트를 일시적으로 일시 중지

  5. 최신 데이터를 새 마스터 테이블로 복사

    INSERT INTO child_2015 (id,counter,dt_created)
    SELECT id,counter,dt_created
    from old_master
    where dt_created >= '01/01/2015'::date AND dt_created < '01/01/2016'::date;
  6. new_master가 프로덕션 데이터베이스가되도록 테이블 이름을 바꾸십시오.

    ALTER TABLE old_master RENAME TO old_master_backup;
    ALTER TABLE new_master RENAME TO old_master;
  7. 데이터가 올바른 파티션으로 전달되도록 INSERT 문에 대한 함수를 old_master에 추가하십시오.

    CREATE OR REPLACE FUNCTION fn_insert() RETURNS TRIGGER AS $$
    BEGIN
        IF ( NEW.dt_created >= DATE '2015-01-01' AND
             NEW.dt_created < DATE '2016-01-01' ) THEN
            INSERT INTO child_2015 VALUES (NEW.*);
        ELSIF ( NEW.dt_created < DATE '2015-01-01' ) THEN
            INSERT INTO child_2014 VALUES (NEW.*);
        ELSE
            RAISE EXCEPTION 'Date out of range';
        END IF;
        RETURN NULL;
    END;
    $$
    LANGUAGE plpgsql;
  8. INSERTS에서 함수가 호출되도록 트리거 추가

    CREATE TRIGGER tr_insert BEFORE INSERT ON old_master
    FOR EACH ROW EXECUTE PROCEDURE fn_insert();
  9. 구속 조건 제외를 ON으로 설정

    SET constraint_exclusion = on;
  10. 프로덕션 데이터베이스에서 UPDATES 및 INSERTS를 다시 활성화하십시오.

  11. 새 파티션을 작성하고 기능을 업데이트하여 올바른 파티션에 새 데이터를 지정하도록 트리거 또는 cron을 설정하십시오. 코드 예제는이 기사를 참조하십시오.

  12. old_master_backup 삭제


1
좋은 글씨. 실제로 쿼리 속도가 빨라지면 흥미로울 것입니다. 천만은 여전히 ​​분할에 대해 생각할만큼 많은 행이 아닙니다. vacuum"유휴중인 트랜잭션"세션으로 인해 성능이 저하 되지 않았는지 또는 성능 저하가 원인인지 궁금 합니다.
a_horse_with_no_name

@a_horse_with_no_name, 지금까지는 쿼리를 크게 개선하지 못했습니다. (자동 진공 설정이있는 Heroku를 사용하며이 큰 테이블에서 매일 발생하는 것처럼 보입니다.
Evan Appleby

3 단계와 5 단계의 삽입물이 new_master를 테이블에 배치하고 postgresql이 올바른 자식 테이블 / 파티션을 선택하도록해서는 안됩니까?
pakman

@pakman 올바른 자녀를 배정하는 기능은 7 단계까지 추가되지 않습니다
Evan Appleby

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.