--1、創建主表 CREATE TABLE tbl_partition ( date_key date, hour_key smallint, client_key integer, item_key integer, account integer, expense numeric ); --2、創建多個分表。每個分區表必須繼承自主表,並且正常情況下都不要為這些分區表添加任何新的列。 CREATE TABLE tbl_partition_2016_01() inherits (tbl_partition); CREATE TABLE tbl_partition_2016_02() inherits (tbl_partition); CREATE TABLE tbl_partition_2016_03() inherits (tbl_partition); --CREATE TABLE tbl_partition_2016_04() inherits (tbl_partition); --3、TODO為分區表添加限制。這些限制決定了該表所能允許保存的數據集范圍。這里必須保證各個分區表之間的限制不能有重疊。 ALTER TABLE tbl_partition_2016_01 ADD CONSTRAINT tbl_partition_2016_01_check_date_key CHECK (date_Key >= '2016-01-01'::date AND date_Key < '2016-02-01'::date); ALTER TABLE tbl_partition_2016_02 ADD CONSTRAINT tbl_partition_2016_02_check_date_key CHECK (date_Key >= '2016-02-01'::date AND date_Key < '2016-03-01'::date); ALTER TABLE tbl_partition_2016_03 ADD CONSTRAINT tbl_partition_2016_03_check_date_key CHECK (date_Key >= '2016-03-01'::date AND date_Key < '2016-04-01'::date); --4、為每一個分區表,在主要的列上創建索引。該索引並不是嚴格必須創建的,但在大部分場景下,它都非常有用。 ---CREATE INDEX tbl_partition_all_date_key ON tbl_partition_all (date_key,client_key); CREATE INDEX tbl_partition_date_key_2016_01 ON tbl_partition_2016_01 (date_key,client_key); CREATE INDEX tbl_partition_date_key_2016_02 ON tbl_partition_2016_02 (date_key,client_key); CREATE INDEX tbl_partition_date_key_2016_03 ON tbl_partition_2016_03 (date_key,client_key); --5、定義一個trigger或者rule把對主表的數據插入操作重定向到對應的分區表。 --創建分區函數 CREATE OR REPLACE FUNCTION tbl_partition_trigger() RETURNS TRIGGER AS $$ BEGIN IF NEW.date_key >= DATE '2016-01-01' AND NEW.date_Key < DATE '2016-02-01' THEN INSERT INTO tbl_partition_2016_01 VALUES (NEW.*); ELSIF NEW.date_key >= DATE '2016-02-01' AND NEW.date_Key < DATE '2016-03-01' THEN INSERT INTO tbl_partition_2016_02 VALUES (NEW.*); ELSIF NEW.date_key >= DATE '2016-03-01' AND NEW.date_Key < DATE '2016-04-01' THEN INSERT INTO tbl_partition_2016_03 VALUES (NEW.*); END IF; RETURN NULL; END; $$ LANGUAGE plpgsql; --6、掛載分區Trigger CREATE TRIGGER insert_tbl_partition_trigger BEFORE INSERT ON tbl_partition FOR EACH ROW EXECUTE PROCEDURE tbl_partition_trigger(); --7、創建全表 CREATE TABLE tbl_partition_all ( date_key date, hour_key smallint, client_key integer, item_key integer, account integer, expense numeric ); --8、自動建表觸發器 CREATE OR REPLACE FUNCTION tbl_partition_trigger() RETURNS TRIGGER AS $$ DECLARE month_text TEXT; this_month_first_day_text TEXT; next_month_first_day_text TEXT; insert_statement TEXT; BEGIN SELECT to_char(NEW.date_key, 'YYYY_MM') INTO month_text; SELECT get_month_first_day(NEW.date_key) INTO this_month_first_day_text; SELECT to_char(to_date(this_month_first_day_text,'YYYY-MM-DD') + interval '1 month', 'YYYY-MM-DD') INTO next_month_first_day_text; insert_statement := 'INSERT INTO tbl_partition_' || month_text||' VALUES ($1.*)'; EXECUTE insert_statement USING NEW; RETURN NULL; EXCEPTION WHEN UNDEFINED_TABLE THEN EXECUTE 'CREATE TABLE IF NOT EXISTS tbl_partition_' || month_text || '(CHECK (date_key >= ''' || this_month_first_day_text || ''' and date_key<''' || next_month_first_day_text || ''')) INHERITS (tbl_partition)'; RAISE NOTICE 'CREATE NON-EXISTANT TABLE tbl_partition_%', month_text; EXECUTE 'CREATE INDEX tbl_partition_date_key_' || month_text || ' ON tbl_partition_' || month_text || '(date_key)'; EXECUTE insert_statement USING NEW; RETURN NULL; END; $$ LANGUAGE plpgsql; --get_month_first_day CREATE OR REPLACE FUNCTION get_month_first_day(in in_date date,out out_date text) AS $$ BEGIN SELECT to_char(in_date, 'YYYY_MM')||'_01' INTO out_date; END; $$ LANGUAGE plpgsql; --插入數據腳本 INSERT INTO tbl_partition_all select (select array_agg(i::date) from generate_series( '2015-12-01'::date, '2015-12-30'::date, '1 day'::interval) as t(i) )[floor(random()*4)+1] as date_key, floor(random()*24) as hour_key, floor(random()*1000000)+1 as client_key, floor(random()*100000)+1 as item_key, floor(random()*20)+1 as account, floor(random()*10000)+1 as expense from generate_series(1,300000000,1); INSERT INTO tbl_partition SELECT * FROM tbl_partition_all; -------------------------------------------------主體結束----------------------------------------- -------------------------------------------------主體結束----------------------------------------- --使用rule創建分表 CREATE RULE tbl_partition_rule_2016_01 AS ON INSERT TO tbl_partition WHERE date_key >= DATE '2016-01-01' AND date_Key < DATE '2016-02-01' DO INSTEAD INSERT INTO tbl_partition_2016_01 VALUES (NEW.*); --刪除繼承關系 ALTER TABLE tbl_partition_2016_01 NO INHERIT tbl_partition; --查詢對比測試 EXPLAIN ANALYZE select count(account) ,client_key from tbl_partition v where v.date_key >='2016-03-02' and v.date_key <='2016-03-07' group by client_key ; EXPLAIN ANALYZE select count(account) ,client_key from tbl_partition_all v where v.date_key >='2016-03-02' and v.date_key <='2016-03-12' group by client_key ;