全部產品
Search
文件中心

AnalyticDB:表分區定義

更新時間:Jun 19, 2024

AnalyticDB PostgreSQL版支援將大表定義為分區表,當您進行條件查詢時,系統只會掃描滿足條件的分區,避免全表掃描,從而提升查詢效能。

支援的表分區類型

  • 範圍(RANGE)分區:基於一個數值型範圍劃分資料,例如按日期區間定義。

  • 值(LIST)分區:基於一個值列表劃分資料,例如按城市屬性定義。

  • 多級分區表:定界分割和值分區的多級組合。

建立範圍(RANGE)分區表

您可以指定一個起始值(START)、一個結束值(END)以及一個定義分區增量值的子句讓資料庫自動產生分區。預設情況下,起始值總是在當前分區中而結束值總是在下個分區中。

建立一個按日期範圍分區的表,樣本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') );

建立一個按數字定界分割的表,例如使用int類型的列作為分區鍵列,樣本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 ); 

建立值(LIST)分區表

LIST分區表可以使用任意允許值比較的列作為分區鍵列。建立LIST分區表時,您必須要為每一個分區聲明每一個值分區。

建立LIST分區表示例如下:

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 );

建立多級分區表

AnalyticDB PostgreSQL版支援建立多級分區表。以下建表示例將建立一個具有三級表分區的表,其中一級分區在year欄位上進行了RANGE分區,二級分區在month欄位上進行了RANGE分區,三級分區在region欄位上進行了LIST分區,樣本如下:

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 );

增加一個分區

您可以通過ALTER TABLE語句為分區表增加一個分區。如果建立分區表時使用了子分區模板,那麼新增的分區也會根據該模板劃分子分區。增加一個分區的樣本如下:

ALTER TABLE sales ADD PARTITION 
            START (date '2017-02-01') INCLUSIVE 
            END (date '2017-03-01') EXCLUSIVE;

如果建立分區表時沒有使用子分區模板,您可以在增加分區時定義子分區,增加一個分區並定義子分區的樣本如下:

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') );

如果需要為現有分區添加一個子分區,您可以指定要更改的分區,樣本SQL如下:

ALTER TABLE sales ALTER PARTITION FOR (RANK(12))
      ADD PARTITION africa VALUES ('africa');
說明

目前不支援對有預設分區的分區表增加分區,如需增加分區請通過分裂預設分區的方法來增加分區。如何分裂分區,請參見分裂一個分區

指定分區子表表名

AnalyticDB PostgreSQL版在6.3.10.9版本之後支援在建立分區表的時候指定分區表子表名,您可以在建立分區子表時添加WITH(tablename=<tablename_1>)子句指定分區子表表名。

樣本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')
);

分裂一個分區

您可以通過ALTER TABLE語句將一個分區劃分成兩個分區。分裂分區存在如下限制:

  • 僅支援分裂最底層的分區,即只有包含資料的分區可以被分裂。

  • 分裂分區語句中指定的分裂值會被分在後一個分區中。

將2017年1月的分區分裂成兩個分區,一個分區包含1月1號至15號,第二個分區包含1月16號至31號,分裂分區的樣本語句如下:

ALTER TABLE sales SPLIT PARTITION FOR ('2017-01-01')
AT ('2017-01-16')
INTO (PARTITION jan171to15, PARTITION jan1716to31);

如果您的分區表中擁有一個預設分區,可以使用分裂預設分區的方法來增加分區。在使用INTO子句時,您需要指定當前的預設分區為第二個分區名。分裂預設分區的樣本語句如下:

ALTER TABLE sales SPLIT DEFAULT PARTITION 
START ('2017-01-01') INCLUSIVE 
END ('2017-02-01') EXCLUSIVE 
INTO (PARTITION jan17, default partition);

分區定義的粒度

在您使用分區表的過程中,可能會遇到分區表粒度的問題,例如按時間分區的情況下,選擇按天、按周還是按月進行分區。分區表的粒度越細,每張分區表的資料就越少,分區表的數量就越多。關於分區表的數量,並沒有絕對的標準,建議分區的數量控制在200以內,分區表數量過多可能會對資料庫使用產生影響,例如查詢最佳化工具產生執行計畫慢,VACUUM執行變慢等。

分區表查詢最佳化

AnalyticDB PostgreSQL版支援分區表的分區裁剪功能,根據查詢條件會只掃描所需的資料分區而避免掃描整個表的全部內容,提升查詢效能。例如對於如下查詢:

EXPLAIN 
  SELECT * FROM sales 
  WHERE year = 2008 
    AND month = 1 
    AND day = 3 
    AND region = 'usa';

查詢條件在一級分區2008的二級子分區1的三級子分區usa上,查詢只會掃描讀取這一個三級子分區資料。如下查詢計劃所示,總計468個三級子分區中,只需要讀取一個分區。

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

查詢分區表定義

您可以通過如下SQL語句查詢分區表的所有分區定義資訊:

SELECT 
  partitionboundary, 
  partitiontablename, 
  partitionname,
  partitionlevel, 
  partitionrank
FROM pg_partitions 
WHERE tablename='sales';

分區表維護

分區表支援多種分區管理操作,包括新增分區,刪除分區,重新命名分區,清空截斷分區,交換分區,分裂分區等,具體資訊,請參見Partitioning Large Tables

分區表子表重新命名

AnalyticDB PostgreSQL版在6.3.10.9版本之後支援對分區表子表重新命名。

如果您需要將子分區表的表名從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:分區鍵必須是主鍵嗎?

A:有主鍵時,分區鍵必須是主鍵之一;沒有主鍵時,分區鍵可以是任意列。