AnalyticDB PostgreSQL版7.0分區表
AnalyticDB PostgreSQL 7.0版對分區表的功能進行了擴展和增強。在AnalyticDB PostgreSQL 6.0版基礎上,新增了對哈希(HASH)分區和表達式分區的支持,并兼容了PostgreSQL12.0版創建分區表和管理分區表的語法。
分區表使用
將大表定義為分區表,從而將其分成較小的存儲單元,根據查詢條件,會只掃描滿足條件的分區而避免全表掃描,從而顯著提升查詢性能。詳細內容,請參見AnalyticDB PostgreSQL版6.0分區表。
創建范圍(RANGE)分區表
您可以先創建范圍(RANGE)分區表,再為該分區表添加子分區,例如:
-- 創建分區表
CREATE TABLE sales (id int, date date, amt decimal(10,2))
DISTRIBUTED BY (id)
PARTITION BY RANGE (date);
-- 添加子分區
CREATE TABLE sales_20160101 PARTITION OF sales
FOR VALUES FROM('2016-01-01') TO ('2016-01-02');
您可以通過給出一個START值、一個END值以及一個定義分區增量值的子句讓數據庫自動產生分區。默認情況下,START值總是被包括在內而END值總是被排除在外,例如:
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'));
您也可以創建一個按數字范圍分區的表,使用同種數據類型列作為其分區鍵列,例如:
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);
創建值 (LIST) 分區表
您可以先創建值(LIST)分區表,再為該分區表添加子分區,例如:
-- 創建分區表
CREATE TABLE rank (id int, rank int, year int, gender
char(1), count int)
DISTRIBUTED BY (id)
PARTITION BY LIST (gender);
-- 添加子分區
CREATE TABLE rank_girls PARTITION OF rank FOR VALUES IN ('F');
按列表分區的表可以使用同種數據類型列作為其分區鍵列。對于列表分區,您必須為每個要創建的分區(列表值)聲明一個分區說明,例如:
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);
創建哈希 (HASH) 分區表
哈希分區會基于分區鍵的哈希值決定數據所在的子分區。您可以先創建哈希 (HASH)分區表,再為該分區表添加子分區。為哈希分區表添加子分區時,MODULUS
子句用于指定除數,REMAINDER
子句用于指定哈希值被除后的余數。
為防止因分區不存在而插入數據失敗,建議在創建哈希分區表后,立即添加分區表下所有的子分區。
-- 創建分區表
CREATE TABLE orders (id int, order_date date, customer_id int, amount decimal)
DISTRIBUTED BY (id)
PARTITION BY HASH (customer_id);
-- 添加子分區
CREATE TABLE orders_p0 PARTITION OF orders FOR VALUES WITH (MODULUS 4, REMAINDER 0);
CREATE TABLE orders_p1 PARTITION OF orders FOR VALUES WITH (MODULUS 4, REMAINDER 1);
CREATE TABLE orders_p2 PARTITION OF orders FOR VALUES WITH (MODULUS 4, REMAINDER 2);
CREATE TABLE orders_p3 PARTITION OF orders FOR VALUES WITH (MODULUS 4, REMAINDER 3);
云原生數據倉庫AnalyticDB PostgreSQL版使用了內置的哈希函數對分區鍵值求取哈希值,提供了系統函數satisfies_hash_partition
供您查詢某個值是否在給定的子分區中。以下SQL語句為查詢public.orders表中customer_id=2的數據是否在MODULUS 4, REMAINDER 0
這個子分區內。
SELECT satisfies_hash_partition('public.orders'::regclass, 4, 0, variadic ARRAY[2]);
哈希 (HASH) 分區表暫不支持在建表時同步創建子分區。
創建表達式分區表
AnalyticDB PostgreSQL 7.0版支持表達式分區,更加靈活易用。
-- 創建分區表--
CREATE TABLE sales (id int, sale_time timestamp, amt decimal(10,2))
DISTRIBUTED BY (id)
PARTITION BY LIST (date_trunc('month', sale_time));
-- 添加子分區
CREATE TABLE sales_202401 PARTITION OF sales FOR VALUES IN('2024-01-01'::timestamp);
創建多級分區表
支持創建多級的分區表。下述建表語句創建了具有三級表分區的表。一級分區在month字段上做RANGE分區,二級分區在region上做了LIST分區。
CREATE TABLE sales(id int, year int, month int, day int, region text)
DISTRIBUTED BY (id)
PARTITION BY RANGE (month)
SUBPARTITION BY LIST (region)
SUBPARTITION TEMPLATE (
SUBPARTITION usa VALUES ('usa'),
SUBPARTITION europe VALUES ('europe'),
SUBPARTITION asia VALUES ('asia'),
DEFAULT SUBPARTITION other_regions)
(START (1) END (13) EVERY (1),
DEFAULT PARTITION other_months);
分區表查詢優化
分區粒度
通常分區表的定義都涉及到粒度問題,比如按時間分區,究竟是按天,按周,按月等。粒度越細,每張表的數據就越少,但是分區的數量就越多,反之亦然。關于分區的數量,沒有絕對的標準,一般分區的數量在200左右已經算是比較多了。分區表數目過多,會有多方面的影響,比如查詢優化器生成執行計劃較慢,同時很多維護工作也會變慢,比如VACUUM等。
對于多級分區表來說,分區文件的數量可能會增長得非常快。例如,如果一個表被按照月和城市劃分并且有24個月以及100個城市,那么表分區的總數就是2400。特別對于列存表,會把每一列存在一個物理表中,因此如果這個表有100個列,系統就需要為該表管理十多萬個文件。因此,在分區表設計之初首先需要考慮未來分區的總數,進而選擇合理的分區定義。
分區裁剪
云原生數據倉庫AnalyticDB PostgreSQL版支持分區表的分區裁剪功能。詳細信息,請參見分區裁剪。
分區表維護
分區表支持多種分區管理操作,包括新增分區,刪除分區,重命名分區,清空分區,交換分區,分裂分區等,下面舉例說明主要操作。
新增分區
如果存在default 分區,則不能新增分區,只能分裂default分區,具體內容見下文分裂分區。
CREATE TABLE sales_p2 PARTITION OF sales FOR VALUES FROM('2017-02-01') TO('2017-02-28');
當分區表已有至少一個子分區時,也可以通過 ALTER TABLE ADD PARTITION 語法來新增分區。
ALTER TABLE sales ADD partition p2 start ('2017-02-01') end ('2017-02-28');
掛載分區
您可以將一張已有的表掛載在表結構相同的分區表的某個子分區上。
ALTER TABLE sales ATTACH PARTITION sales_p2 FOR VALUES FROM('2017-02-01') TO('2017-02-28');
卸載分區
卸載分區只是解除分區主表與子表的關系,不會真正刪除分區子表。
ALTER TABLE sales DETACH PARTITION sales_p2;
刪除分區
刪除分區會直接刪除分區子表。
ALTER TABLE sales DROP PARTITION p2;
重命名分區
ALTER TABLE sales RENAME PARTITION p2 TO Feb17;
清空分區
ALTER TABLE sales TRUNCATE PARTITION p1;
交換分區
ALTER TABLE sales EXCHANGE PARTITION p2 WITH TABLE {cos_table_name} ;
分裂分區
-- 將分區p3 在 '2017-03-20' 左右切分成兩塊 ALTER TABLE sales SPLIT partition p3 at ('2017-03-20') into (partition p2, partition p3);
當已有default分區時,只能通過分裂default分區來新增分區。
ALTER TABLE sales SPLIT DEFAULT PARTITION START('2017-03-01') END('2017-03-31') into(partition p3, default partition);