1M +行のテーブルを日付範囲で分割したいと思います。多くのダウンタイムを必要とせずに、またはデータを失うリスクなしに、これはどのように一般的に行われますか?以下は私が検討している戦略ですが、提案を受け付けています。
既存のテーブルはマスターであり、子はテーブルから継承します。時間の経過とともにデータをマスターから子に移動しますが、一部のデータがマスターテーブルにあり、一部が子にある期間があります。
新しいマスターテーブルと子テーブルを作成します。子テーブルの既存のテーブルにデータのコピーを作成します(データは2か所に存在します)。子テーブルに最新のデータが格納されたら、すべての挿入を新しいマスターテーブルを指すように変更し、既存のテーブルを削除します。
#1はアクティブな実稼働環境にあるときにマスターから子にデータをコピーする必要があるため、私は#2(新しいマスターの作成)を個人的に行いました。これにより、元のテーブルがアクティブに使用されているときに元のテーブルが中断されることがなくなります。問題が発生した場合は、問題なく新しいマスターを簡単に削除して、元のテーブルを引き続き使用できます。これを行う手順は次のとおりです。
新しいマスターテーブルを作成します。
CREATE TABLE new_master (
id serial,
counter integer,
dt_created DATE DEFAULT CURRENT_DATE NOT NULL
);
マスターから継承する子を作成します。
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);
...
すべての履歴データを新しいマスターテーブルにコピーする
INSERT INTO child_2014 (id,counter,dt_created)
SELECT id,counter,dt_created
from old_master
where dt_created < '01/01/2015'::date;
本番データベースへの新しい挿入/更新を一時的に一時停止します
最新のデータを新しいマスターテーブルにコピーする
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;
New_masterが本番データベースになるようにテーブルの名前を変更します。
ALTER TABLE old_master RENAME TO old_master_backup;
ALTER TABLE new_master RENAME TO old_master;
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;
INSERTSで関数が呼び出されるようにトリガーを追加する
CREATE TRIGGER tr_insert BEFORE INSERT ON old_master
FOR EACH ROW EXECUTE PROCEDURE fn_insert();
制約の除外をオンに設定します
SET constraint_exclusion = on;
本番データベースで更新と挿入を再度有効にします
新しいパーティションが作成され、関数が更新されて新しいデータを正しいパーティションに割り当てるように、トリガーまたはcronを設定します。 コード例については、この記事を参照してください
Old_master_backupを削除します
これを自動的に行うpg_pathman( https://github.com/postgrespro/pg_pathman )と呼ばれる新しいツールがあります。
したがって、次のようなものがそれを行います。
SELECT create_range_partitions('master', 'dt_created',
'2015-01-01'::date, '1 day'::interval);