テーブルパーティショニング
PostgreSQLのテーブルパーティショニングめも。
PostgreSQLでは、テーブル継承を利用してテーブルパーティショニングを行うことができます。
例えば、三ヶ月以上前のデータを一ヶ月単位で削除するようなシステムの場合、月ごとにテーブルを分けることで削除処理をスムーズに行うことができます。
月ごとにテーブルパーティショニングを行う例
概要
・データを格納しない親テーブルを作成する。
・月ごとのデータを格納する継承テーブルを作成する。
・INSERT時、継承テーブルにデータが挿入されるようなテーブルルールを作成する。
・親テーブルにINSERTトリガとしてテーブルルールを設定する。
実装例
親テーブル
CREATE TABLE sample ( id serial NOT NULL, --ID name text NOT NULL, --名前 status smallint, --ステータス ins_date timestamp without time zone, --作成日時 CONSTRAINT sample_pkey PRIMARY KEY (id) ) WITH (OIDS=FALSE);
継承テーブル
CREATE TABLE sample_00() INHERITS (sample); CREATE TABLE sample_01() INHERITS (sample); CREATE TABLE sample_02() INHERITS (sample); CREATE TABLE sample_03() INHERITS (sample);
テーブルルール
CREATE OR REPLACE FUNCTION sample_insert_func() RETURNS TRIGGER AS $$ DECLARE suffix int8 ; BEGIN suffix := cast(date_part('month', NEW.ins_date) as integer) % 4 ; IF ( suffix = 1 ) THEN INSERT INTO sample_01 VALUES (NEW.*); ELSIF ( suffix = 2 ) THEN INSERT INTO sample_02 VALUES (NEW.*); ELSIF ( suffix = 3 ) THEN INSERT INTO sample_03 VALUES (NEW.*); ELSE INSERT INTO sample_00 VALUES (NEW.*); END IF; RETURN NEW; END; $$ LANGUAGE plpgsql;
INSERTトリガ
CREATE TRIGGER sample_insert_trig BEFORE INSERT ON sample FOR EACH ROW EXECUTE PROCEDURE sample_insert_func();
注意点
問い合わせ
親テーブル(ここでは、sampleテーブル)に対してクエリを発行すると、継承テーブル全てに対して問い合わせが行われます。
explainのイメージ
QUERY PLAN ------------------------------------------------------------------------------------------------------------------- Result (cost=0.00..411.04 rows=203 width=38) -> Append (cost=0.00..411.04 rows=203 width=38) -> Index Scan using sample_00_id on sample_00 sample (cost=0.00..165.86 rows=84 width=38) Index Cond: (id = 10) -> Index Scan using sample_01_id on sample_01 sample (cost=0.00..68.86 rows=34 width=38) Index Cond: (id = 10) -> Index Scan using sample_02_id on sample_02 sample (cost=0.00..73.57 rows=36 width=38) Index Cond: (id = 10) -> Index Scan using sample_03_id on sample_03 sample (cost=0.00..38.69 rows=18 width=38) Index Cond: (id = 10)
特定のテーブルのみに問い合わせを行いたい場合は、onlyを付けます。
-- sample(親テーブル)のみ検索。この例の場合は、データは格納されていません。 select * from only sample where id = 10; -- sample_00、sample_01のみ検索 select * from only sample_00 sample_01 where id = 10;
インデックス
親テーブルに作成したインデックスは、継承テーブルに対して有効ではありません。
以下のように、継承テーブルごとにインデックスを作成する必要があります。
CREATE INDEX sample_00_ins_date ON sample_00 (ins_date); CREATE INDEX sample_01_ins_date ON sample_01 (ins_date); CREATE INDEX sample_02_ins_date ON sample_02 (ins_date); CREATE INDEX sample_03_ins_date ON sample_03 (ins_date);
トランザクション
8.3.x以前のバージョンでは、継承テーブルの悲観的ロックがサポートされていません。
ですので、以下のようなクエリはエラーとなってしまいます。
(ERROR: SELECT FOR UPDATE/SHARE is not supported for inheritance queries)
8.4以降ではサポートされています。
begin; select id from sample where id = 100 for update; update sample set status = 2 where id = 100; commit;
チェック制約
チェック制約を付けることで、親テーブルの問い合わせ効率が改善することがあります。
CREATE TABLE sample_01 ( CHECK ( ins_date >= DATE '2011-01-01' AND ins_date < DATE '2011-02-01' ) ) INHERITS (sample);