表分區(qū)定義
AnalyticDB PostgreSQL版支持將大表定義為分區(qū)表,當(dāng)您進(jìn)行條件查詢時,系統(tǒng)只會掃描滿足條件的分區(qū),避免全表掃描,從而提升查詢性能。
支持的表分區(qū)類型
范圍(RANGE)分區(qū):基于一個數(shù)值型范圍劃分?jǐn)?shù)據(jù),例如按日期區(qū)間定義。
值(LIST)分區(qū):基于一個值列表劃分?jǐn)?shù)據(jù),例如按城市屬性定義。
多級分區(qū)表:范圍分區(qū)和值分區(qū)的多級組合。
創(chuàng)建范圍(RANGE)分區(qū)表
您可以指定一個起始值(START)、一個結(jié)束值(END)以及一個定義分區(qū)增量值的子句讓數(shù)據(jù)庫自動產(chǎn)生分區(qū)。默認(rèn)情況下,起始值總是在當(dāng)前分區(qū)中而結(jié)束值總是在下個分區(qū)中。
創(chuàng)建一個按日期范圍分區(qū)的表,示例SQL如下:
CREATE TABLE sales (id int, date date, amt decimal(10,2))
DISTRIBUTED BY (id)
PARTITION BY RANGE (date)
( START (date '2016-01-01') INCLUSIVE
END (date '2017-01-01') EXCLUSIVE
EVERY (INTERVAL '1 day') );
創(chuàng)建一個按數(shù)字范圍分區(qū)的表,例如使用int類型的列作為分區(qū)鍵列,示例SQL如下:
CREATE TABLE rank (id int, rank int, year int, gender char(1), count int)
DISTRIBUTED BY (id)
PARTITION BY RANGE (year)
( START (2006) END (2016) EVERY (1),
DEFAULT PARTITION extra );
創(chuàng)建值(LIST)分區(qū)表
LIST分區(qū)表可以使用任意允許值比較的列作為分區(qū)鍵列。創(chuàng)建LIST分區(qū)表時,您必須要為每一個分區(qū)聲明每一個值分區(qū)。
創(chuàng)建LIST分區(qū)表示例如下:
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 );
創(chuàng)建多級分區(qū)表
AnalyticDB PostgreSQL版支持創(chuàng)建多級分區(qū)表。以下建表示例將創(chuàng)建一個具有三級表分區(qū)的表,其中一級分區(qū)在year字段上進(jìn)行了RANGE分區(qū),二級分區(qū)在month字段上進(jìn)行了RANGE分區(qū),三級分區(qū)在region字段上進(jìn)行了LIST分區(qū),示例如下:
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 (2012) EVERY (1),
DEFAULT PARTITION outlying_years );
增加一個分區(qū)
您可以通過ALTER TABLE語句為分區(qū)表增加一個分區(qū)。如果創(chuàng)建分區(qū)表時使用了子分區(qū)模板,那么新增的分區(qū)也會根據(jù)該模板劃分子分區(qū)。增加一個分區(qū)的示例如下:
ALTER TABLE sales ADD PARTITION
START (date '2017-02-01') INCLUSIVE
END (date '2017-03-01') EXCLUSIVE;
如果創(chuàng)建分區(qū)表時沒有使用子分區(qū)模板,您可以在增加分區(qū)時定義子分區(qū),增加一個分區(qū)并定義子分區(qū)的示例如下:
ALTER TABLE sales ADD PARTITION
START (date '2017-02-01') INCLUSIVE
END (date '2017-03-01') EXCLUSIVE
( SUBPARTITION usa VALUES ('usa'),
SUBPARTITION asia VALUES ('asia'),
SUBPARTITION europe VALUES ('europe') );
如果需要為現(xiàn)有分區(qū)添加一個子分區(qū),您可以指定要更改的分區(qū),示例SQL如下:
ALTER TABLE sales ALTER PARTITION FOR (RANK(12))
ADD PARTITION africa VALUES ('africa');
目前不支持對有默認(rèn)分區(qū)的分區(qū)表增加分區(qū),如需增加分區(qū)請通過分裂默認(rèn)分區(qū)的方法來增加分區(qū)。如何分裂分區(qū),請參見分裂一個分區(qū)。
指定分區(qū)子表表名
AnalyticDB PostgreSQL版在6.3.10.9版本之后支持在創(chuàng)建分區(qū)表的時候指定分區(qū)表子表名,您可以在創(chuàng)建分區(qū)子表時添加WITH(tablename=<tablename_1>)
子句指定分區(qū)子表表名。
示例SQL如下:
CREATE TABLE partition_with_name_list (a int, b int, c int) DISTRIBUTED BY (a) PARTITION BY LIST (a)
(
PARTITION p1 VALUES (1) WITH (tablename='partition_with_name_list_p1'),
PARTITION p2 VALUES (2) WITH (tablename='partition_with_name_list_p2'),
PARTITION p3 VALUES (3) WITH (tablename='partition_with_name_list_p3'),
PARTITION p4 VALUES (4) WITH (tablename='partition_with_name_list_p4')
);
分裂一個分區(qū)
您可以通過ALTER TABLE語句將一個分區(qū)劃分成兩個分區(qū)。分裂分區(qū)存在如下限制:
僅支持分裂最底層的分區(qū),即只有包含數(shù)據(jù)的分區(qū)可以被分裂。
分裂分區(qū)語句中指定的分裂值會被分在后一個分區(qū)中。
將2017年1月的分區(qū)分裂成兩個分區(qū),一個分區(qū)包含1月1號至15號,第二個分區(qū)包含1月16號至31號,分裂分區(qū)的示例語句如下:
ALTER TABLE sales SPLIT PARTITION FOR ('2017-01-01')
AT ('2017-01-16')
INTO (PARTITION jan171to15, PARTITION jan1716to31);
如果您的分區(qū)表中擁有一個默認(rèn)分區(qū),可以使用分裂默認(rèn)分區(qū)的方法來增加分區(qū)。在使用INTO子句時,您需要指定當(dāng)前的默認(rèn)分區(qū)為第二個分區(qū)名。分裂默認(rèn)分區(qū)的示例語句如下:
ALTER TABLE sales SPLIT DEFAULT PARTITION
START ('2017-01-01') INCLUSIVE
END ('2017-02-01') EXCLUSIVE
INTO (PARTITION jan17, default partition);
分區(qū)定義的粒度
在您使用分區(qū)表的過程中,可能會遇到分區(qū)表粒度的問題,例如按時間分區(qū)的情況下,選擇按天、按周還是按月進(jìn)行分區(qū)。分區(qū)表的粒度越細(xì),每張分區(qū)表的數(shù)據(jù)就越少,分區(qū)表的數(shù)量就越多。關(guān)于分區(qū)表的數(shù)量,并沒有絕對的標(biāo)準(zhǔn),建議分區(qū)的數(shù)量控制在200以內(nèi),分區(qū)表數(shù)量過多可能會對數(shù)據(jù)庫使用產(chǎn)生影響,例如查詢優(yōu)化器生成執(zhí)行計(jì)劃慢,VACUUM執(zhí)行變慢等。
對于多級分區(qū)表需要格外注意,多級分區(qū)的數(shù)量可能會增長得非常快。例如,一張表按月份和城市進(jìn)行分區(qū),劃分了24個月和100個城市,那么該表的分區(qū)總數(shù)就達(dá)到了2400,若該表為列存表的話,數(shù)據(jù)庫會把每一列數(shù)據(jù)存在一個物理表中,假如該表有100個列,系統(tǒng)就需要為該表管理上萬個文件。
分區(qū)表查詢優(yōu)化
AnalyticDB PostgreSQL版支持分區(qū)表的分區(qū)裁剪功能,根據(jù)查詢條件會只掃描所需的數(shù)據(jù)分區(qū)而避免掃描整個表的全部內(nèi)容,提升查詢性能。例如對于如下查詢:
EXPLAIN
SELECT * FROM sales
WHERE year = 2008
AND month = 1
AND day = 3
AND region = 'usa';
查詢條件在一級分區(qū)2008的二級子分區(qū)1的三級子分區(qū)usa上,查詢只會掃描讀取這一個三級子分區(qū)數(shù)據(jù)。如下查詢計(jì)劃所示,總計(jì)468個三級子分區(qū)中,只需要讀取一個分區(qū)。
Gather Motion 4:1 (slice1; segments: 4) (cost=0.00..431.00 rows=1 width=24)
-> Sequence (cost=0.00..431.00 rows=1 width=24)
-> Partition Selector for sales (dynamic scan id: 1) (cost=10.00..100.00 rows=25 width=4)
Filter: year = 2008 AND month = 1 AND region = 'usa'::text
Partitions selected: 1 (out of 468)
-> Dynamic Table Scan on sales (dynamic scan id: 1) (cost=0.00..431.00 rows=1 width=24)
Filter: year = 2008 AND month = 1 AND day = 3 AND region = 'usa'::text
查詢分區(qū)表定義
您可以通過如下SQL語句查詢分區(qū)表的所有分區(qū)定義信息:
SELECT
partitionboundary,
partitiontablename,
partitionname,
partitionlevel,
partitionrank
FROM pg_partitions
WHERE tablename='sales';
分區(qū)表維護(hù)
分區(qū)表支持多種分區(qū)管理操作,包括新增分區(qū),刪除分區(qū),重命名分區(qū),清空截?cái)喾謪^(qū),交換分區(qū),分裂分區(qū)等,具體信息,請參見Partitioning Large Tables。
分區(qū)表子表重命名
AnalyticDB PostgreSQL版在6.3.10.9版本之后支持對分區(qū)表子表重命名。
如果您需要將子分區(qū)表的表名從partition_with_name_list_p1
改為partition_with_name_list_p1r
,示例SQL如下:
ALTER TABLE partition_with_name_list_p1 RENAME TO partition_with_name_list_p1r;
常見問題
Q:分區(qū)鍵必須是主鍵嗎?
A:有主鍵時,分區(qū)鍵必須是主鍵之一;沒有主鍵時,分區(qū)鍵可以是任意列。