1、定義日期範圍分區表
日期範圍分區表使用單個date或者timestamp字段作爲分區鍵。
可以通過使用START值、 END值和EVERY子句定義分區增量讓GPDB自動產生分區。
缺省情況下, START值總是被包含而END值總是被排除(左閉右開)。
CREATE TABLE sales
(
id int
, date date
, amt decimal(10,2)
)
DISTRIBUTED BY (id)
PARTITION BY RANGE (date)
(
START (date '2018-01-01') INCLUSIVE
END (date '2019-01-01') EXCLUSIVE
EVERY (INTERVAL '1 day')
);
不過也可以爲每個分區單獨指定名稱。比如:
CREATE TABLE sales (id int, date date, amt decimal(10,2))
DISTRIBUTED BY (id)
PARTITION BY RANGE (date)
( PARTITION Jan08 START (date '2008-01-01') INCLUSIVE ,
PARTITION Feb08 START (date '2008-02-01') INCLUSIVE ,
PARTITION Mar08 START (date '2008-03-01') INCLUSIVE ,
PARTITION Apr08 START (date '2008-04-01') INCLUSIVE ,
PARTITION May08 START (date '2008-05-01') INCLUSIVE ,
PARTITION Jun08 START (date '2008-06-01') INCLUSIVE ,
PARTITION Jul08 START (date '2008-07-01') INCLUSIVE ,
PARTITION Aug08 START (date '2008-08-01') INCLUSIVE ,
PARTITION Sep08 START (date '2008-09-01') INCLUSIVE ,
PARTITION Oct08 START (date '2008-10-01') INCLUSIVE ,
PARTITION Nov08 START (date '2008-11-01') INCLUSIVE ,
PARTITION Dec08 START (date '2008-12-01') INCLUSIVE END (date '2009-01-01') EXCLUSIVE
);
上面的分區的範圍都是連續的,如果不連續需要指定end值。
2、定義數字範圍分區表
數字範圍分區表使用單個數字列作爲分區鍵。例如:
CREATE TABLE rank (id int
, rank int
, year int
, gender char(1)
, count int)
DISTRIBUTED BY (id)
PARTITION BY RANGE (year)
( START (2001) END (2008) EVERY (1),
DEFAULT PARTITION extra
);
3、定義列表分區表
列表分區表可以使用任何數據類型的列作爲分區鍵,分區規則使用等值比較。
列表分區可以使用多個COLUMN(組合起來)作爲分區鍵,而範圍分區只允許使用單獨COLUMN作爲分區鍵。對於列表分區,必須爲每個分區指定相應的值。
CREATE TABLE rank (id int, rank int, year int, gender char(1), count int )
DISTRIBUTED BY (id)
PARTITION BY LIST (gender)
(
PARTITION girls VALUES ('F'),
PARTITION boys VALUES ('M'),
DEFAULT PARTITION other
);
4、定義多級分區表
使用SUBPARTITION TEMPLATE來確保每個分區具有相同的子分區結構,尤其是對那些後增加的分區來說。
CREATE TABLE sales (trans_id int, date date, amount decimal(9,2), region text)
DISTRIBUTED BY (trans_id)
PARTITION BY RANGE (date)
SUBPARTITION BY LIST (region)
SUBPARTITION TEMPLATE
(
SUBPARTITION usa VALUES ('usa'),
SUBPARTITION asia VALUES ('asia'),
SUBPARTITION europe VALUES ('europe'),
DEFAULT SUBPARTITION other_regions
)
( START (date '2008-01-01') INCLUSIVE END (date '2009-01-01') EXCLUSIVE
EVERY (INTERVAL '1 month'),
DEFAULT PARTITION outlying_dates
);
下面是一個3級分區表的例子,這裏表sales被分區爲年、月、區域。 SUBPARTITION TEMPLATE子句確保每個年分區有相同的子分區結構。
另外,每個級別的分區都有一個默認分區:
CREATE TABLE sales (id int, year int, month int, day int, region text) DISTRIBUTED BY (id)
PARTITION BY RANGE (year)
SUBPARTITION BY RANGE (month)
SUBPARTITION TEMPLATE
(
START (1) END (13) EVERY (1),
DEFAULT SUBPARTITION other_months
)
SUBPARTITION BY LIST (region)
SUBPARTITION TEMPLATE
(
SUBPARTITION usa VALUES ('usa'),
SUBPARTITION europe VALUES ('europe'),
SUBPARTITION asia VALUES ('asia'),
DEFAULT SUBPARTITION other_regions
)
( START (2002) END (2010) EVERY (1),
DEFAULT PARTITION outlying_years
);
將現有表分區
對已經創建的表是不能分區的。只能在CREATE TABLE的時候做分區。要想對現有的表做分區,只能重新創建一個分區表、重新裝載數據到新的分區表中、刪掉舊錶然後把新的分區表改爲舊錶的名稱。還必須重新對TABLE做授權。
CREATE TABLE sales2 (LIKE sales)
PARTITION BY RANGE (date)
( START (date '1998-01-01') INCLUSIVE END (date '2002-01-01') EXCLUSIVE
EVERY (INTERVAL '1 month')
);
INSERT INTO sales2 SELECT * FROM sales;
DROP TABLE sales;
ALTER TABLE sales2 RENAME TO sales;
GRANT ALL PRIVILEGES ON sales TO admin;
GRANT SELECT ON sales TO guest;
分區表的限制
主鍵或者唯一約束必須包含表上的所有分區鍵。而唯一索引可以不包含分區鍵,但是,其只對一個分區強制有效,而不是對整個分區表有效。
裝載分區表
一旦創建了分區表,頂級表總是空的。數據值儲存在最低層的表中。在多級分區表中,僅僅在層級最低的子分區中有數據。
在運行期間,查詢規劃器會掃描整個TABLE的層級結構並使用CHECK約束適配查詢條件來決定哪些子表需要被掃描。
默認分區(只要該層級中存在)總是會被掃描。如果默認分區中包含數據,其會拖慢整體的掃表時間。
如果有必要,還可以直接把數據裝載到子表中。還可以先創建一箇中間表、裝載數據、然後與分區表進行分區交換。這種分區交換的性能高於直接的COPY和INSERT。
查看分區設計
要查看分區表的設計情況,通過pg_partitions視圖查看。
SELECT
partitionboundary
, partitiontablename
, partitionname
, partitionlevel
, partitionrank
FROM pg_partitions WHERE tablename='sales2';
pg_partition_templates - 用以創建SUBPARTITION的SUBPARTITION template
pg_partition_columns – 用於分區的分區鍵
維護分區表
必須使用ALTER TABLE命令從頂級表來維護分區。
- 最常見的場景是根據日期範圍的設計來維護數據時,刪除舊分區並添加一個新的分區。
- 把舊的分區交換爲壓縮AO表以節省空間。
若在父表中存在默認分區,添加分區的操作只能是從默認分區拆分出一個新的分區。
由於分區不要求有名稱,若分區沒有名稱,下面的表達式仍可以指定一個分區:
PARTITION FOR (value) or PARTITION FOR(RANK(number))
(1) 添加新分區
如果原有的分區表包含了subpartition template設計,新增的分區將根據該模版創建子分區。
CREATE TABLE sales (trans_id int, date char(8), amount decimal(9,2), region text)
DISTRIBUTED BY (trans_id)
PARTITION BY RANGE (date)
SUBPARTITION BY LIST (region)
SUBPARTITION TEMPLATE
(
SUBPARTITION usa VALUES ('usa'),
SUBPARTITION asia VALUES ('asia'),
SUBPARTITION europe VALUES ('europe'),
DEFAULT SUBPARTITION other_regions
)
( START ('2008-01-01') INCLUSIVE END ('2009-01-01') EXCLUSIVE
EVERY (INTERVAL '1 month'),
DEFAULT PARTITION outlying_dates
);
ALTER TABLE sales ADD PARTITION
START (date '2009-02-01') INCLUSIVE
END (date '2009-03-01') EXCLUSIVE;
如果在創建TABLE時沒有subpartition template,在新增分區時需要定義子分區:
ALTER TABLE sales ADD PARTITION
START (date '2009-02-01') INCLUSIVE
END (date '2009-03-01') EXCLUSIVE
( SUBPARTITION usa VALUES ('usa'),
SUBPARTITION asia VALUES ('asia'),
SUBPARTITION europe VALUES ('europe') );
子表的名稱格式如下:
<父表名稱>_<分區層級>prt<分區名稱>
子表的名稱不能通過直接執行ALTER表名來實現。但修改頂級表的名稱,該改變將會影響所有相關的分區表。
添加缺省分區
ALTER TABLE sales ADD DEFAULT PARTITION other;
如果是多級分區表, 同一層次中的每個分區都需要一個默認分區。
ALTER TABLE sales ALTER PARTITION FOR (RANK(1)) ADD DEFAULT PARTITION other;
ALTER TABLE sales ALTER PARTITION FOR (RANK(2)) ADD DEFAULT PARTITION other;
ALTER TABLE sales ALTER PARTITION FOR (RANK(3)) ADD DEFAULT PARTITION other;
RANK(partitionrank)指的是範圍分區同一層級中的順序。partitionrank可參見pg_partition表。
(2)刪除分區
ALTER TABLE sales DROP PARTITION FOR (RANK(1));
注意: 在將RANK(1)的分區刪除後,其餘分區的partitionrank值仍然是從1開始的連續編號。 編號的順序按照分區字段的值由小到大從1開始排序。
不管分區是否連續(中間有值不匹配分區),或者隨意的修改分區定義。
(3)清空分區數據
在清空一個包含子分區的分區時,其所有相關子分區的數據都自動被清空。
ALTER TABLE sales TRUNCATE PARTITION FOR (RANK(1));
(4)交換分區:
CREATE TABLE jan08 (LIKE sales) WITH (appendonly=true);
INSERT INTO jan08 SELECT * FROM sales_1_prt_1 ;
ALTER TABLE sales EXCHANGE PARTITION FOR (DATE '2008-01-01') WITH TABLE jan08
(5)拆分分區
拆分分區是將現有的一個分區分成兩個分區。 使用ALTER TABLE命令來拆分分區。
只能拆分最低層級的分區表(只有包含數據的分區可以拆分)。
指定的分割值對應的數據將進入後面一個分區(就是STAER爲INCLUSIVE)。
ALTER TABLE sales SPLIT PARTITION FOR ('2008-01-01')
AT ('2008-01-16') INTO (PARTITION jan081to15, PARTITION jan0816to31);
如果分區表有默認分區,要添加新的分區只能從默認分區拆分。而且只能從最低層級分區的默認分區拆分(只有包含數據的分區可以拆分)。
在使用INTO子句時,第2個分區名稱必須是已經存在的默認分區。
ALTER TABLE sales SPLIT DEFAULT PARTITION
START ('2009-01-01') INCLUSIVE
END ('2009-02-01') EXCLUSIVE
INTO (PARTITION jan09, default partition);
(6)修改子分區模版
使用ALTER TABLE SET SUBPARTITION TEMPLATE命令來修改現有分區表的子分區模版。 在修改了子分區模版之後添加的分區,其子分區將按照新的模版產生。已經存在的分區不會被修改。
ALTER TABLE sales SET SUBPARTITION TEMPLATE
( SUBPARTITION usa VALUES ('usa'),
SUBPARTITION asia VALUES ('asia'),
SUBPARTITION europe VALUES ('europe'),
SUBPARTITION africa VALUES ('africa')
DEFAULT SUBPARTITION other
);
ALTER TABLE sales ADD PARTITION sales_prt_3
START ('2009-03-01') INCLUSIVE END ('2009-04-01') EXCLUSIVE;
這個例子在一級分區有默認分區時是不能執行的,要查看效果,先刪除默認分區。
要刪除子分區模版,使用SET SUBPARTITION TEMPLATE並使用空的參數來完成。
ALTER TABLE sales SET SUBPARTITION TEMPLATE ();