LoginSignup
3
5

More than 5 years have passed since last update.

PostgreSQLにおけるパーティショニングの実装

Last updated at Posted at 2017-05-09

大規模なテーブルを展開して処理する前処理プログラムを書いている中で,そもそも自機のメモリにデータが全展開するだけの容量がなく,プログラムを複数回に分散して省メモリ化したいと考えたので,今後のためにもテーブルパーティションに関してメモしておく.

実はPostgreSQLではパーティショニングに関する専用の組み込み機能を持たないらしい..そこでテーブルの継承を利用して機能を実装する.

親テーブル(マスターテーブル)の定義

まず最初に全てのパーティションが継承する親テーブルを宣言する.このテーブルには実データを格納せずに全て子テーブルに分散して格納する.

## サンプルテーブル

CREATE TABLE test (
    id bigint PRIMARY KEY,
    name character varying,
    date timestamp without time zone,
    content character varying
);

子テーブル(サブテーブル)の定義

次に,実データの格納先となる親テーブルを継承した子テーブル定義する.テーブルにはそれぞれCHECKで検査制約を付与する.この検査制約によってデータの格納するパーティションを決定するが,この時に1つのデータが複数のパーティションに共存しないように検査制約を設定する必要がある.

CREATE TABLE test_2012 (
    CHECK ( date >= TIMESTAMP WITHOUT TIME ZONE '2012-01-01' AND date < TIMESTAMP WITHOUT TIME ZONE '2013-01-01')
) INHERITS (test);
CREATE TABLE test_2013 (
    CHECK ( date >= TIMESTAMP WITHOUT TIME ZONE '2013-01-01' AND date < TIMESTAMP WITHOUT TIME ZONE '2014-01-01')
) INHERITS (test);
CREATE TABLE test_2014 (
    CHECK ( date >= TIMESTAMP WITHOUT TIME ZONE '2014-01-01' AND date < TIMESTAMP WITHOUT TIME ZONE '2015-01-01')
) INHERITS (test);
CREATE TABLE test_2015 (
    CHECK ( date >= TIMESTAMP WITHOUT TIME ZONE '2015-01-01' AND date < TIMESTAMP WITHOUT TIME ZONE '2016-01-01')
) INHERITS (test);
CREATE TABLE test_2016 (
    CHECK ( date >= TIMESTAMP WITHOUT TIME ZONE '2016-01-01' AND date < TIMESTAMP WITHOUT TIME ZONE '2017-01-01')
) INHERITS (test);

同時に,この検査制約によってINSERTに遅延が発生するので各子テーブルにインデックスを貼り処理の高速化を計る.

CREATE INDEX test_2012_date_idx ON test_2012 (date);
CREATE INDEX test_2013_date_idx ON test_2013 (date);
CREATE INDEX test_2014_date_idx ON test_2014 (date);
CREATE INDEX test_2015_date_idx ON test_2015 (date);
CREATE INDEX test_2016_date_idx ON test_2016 (date);

トリガ関数の定義

最後に親テーブルにデータがINSERTされた時に,適切なパーティションにデータが中継されるようにトリガ関数を定義する.

CREATE OR REPLACE FUNCTION test_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
    IF ( NEW.date >= TIMESTAMP WITHOUT TIME ZONE '2012-01-01' AND
         NEW.date < TIMESTAMP WITHOUT TIME ZONE '2013-01-01' ) THEN
        INSERT INTO test_2012 VALUES (NEW.*);
    ELSIF ( NEW.date >= TIMESTAMP WITHOUT TIME ZONE '2013-01-01' AND
            NEW.date < TIMESTAMP WITHOUT TIME ZONE '2014-01-01' ) THEN
        INSERT INTO test_2013 VALUES (NEW.*);
    ...
    ELSIF ( NEW.date >= TIMESTAMP WITHOUT TIME ZONE '2016-01-01' AND
            NEW.date < TIMESTAMP WITHOUT TIME ZONE '2017-01-01' ) THEN
        INSERT INTO test_2016 VALUES (NEW.*);
    ELSE
        RAISE EXCEPTION 'Date out of range.  Fix the test_insert_trigger() function.';
    END IF;
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;

この関数を定義した後,上記のトリガ関数をクライアントからのINSERTからよぶトリガをテーブルに定義して完了である.

CREATE TRIGGER insert_test_trigger
    BEFORE INSERT ON test
    FOR EACH ROW EXECUTE PROCEDURE test_insert_trigger();

3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5