Updated on 2024-06-07 GMT+08:00

Range Partitioning

Range partitioning maps data to partitions based on the value range of the partition key created for each partition. Range partitioning is the most common partitioning type in production systems and is usually used in scenarios where data is described by date or timestamp. There are two syntax formats for range partitioning. The following is an example:

  1. VALUES LESS THAN

    If the VALUE LESS THAN clause is used, a range partitioning policy supports a partition key with up to 16 columns.

    • The following is an example of a single-column partition key:
      gaussdb=# CREATE TABLE range_sales
      (
          product_id      INT4 NOT NULL,
          customer_id     INT4 NOT NULL,
          time            DATE,
          channel_id      CHAR(1),
          type_id         INT4,
          quantity_sold   NUMERIC(3),
          amount_sold     NUMERIC(10,2)
      )
      PARTITION BY RANGE (time)
      (
          PARTITION date_202001 VALUES LESS THAN ('2020-02-01'),
          PARTITION date_202002 VALUES LESS THAN ('2020-03-01'),
          PARTITION date_202003 VALUES LESS THAN ('2020-04-01'),
          PARTITION date_202004 VALUES LESS THAN ('2020-05-01')
      );
      
      gaussdb=# DROP TABLE range_sales;

      date_202002 indicates the partition of February 2020, which contains the data of the partition key from February 1, 2020 to February 29, 2020.

      Each partition has a VALUES LESS clause that specifies the upper limit (excluded) of the partition. Any value greater than or equal to that partition key will be added to the next partition. Except the first partition, all partitions have an implicit lower limit specified by the VALUES LESS clause of the previous partition. You can define the MAXVALUE keyword for the last partition. MAXVALUE represents a virtual infinite value that is prior to any other possible value (including null) of the partition key.

    • The following is an example of a multi-column partition key:
      gaussdb=# CREATE TABLE range_sales_with_multiple_keys
      (
          c1      INT4 NOT NULL,
          c2      INT4 NOT NULL,
          c3      CHAR(1)
      )
      PARTITION BY RANGE (c1,c2)
      (
          PARTITION p1 VALUES LESS THAN (10,10),
          PARTITION p2 VALUES LESS THAN (10,20),
          PARTITION p3 VALUES LESS THAN (20,10)
      );
      gaussdb=# INSERT INTO range_sales_with_multiple_keys VALUES(9,5,'a');
      gaussdb=# INSERT INTO range_sales_with_multiple_keys VALUES(9,20,'a');
      gaussdb=# INSERT INTO range_sales_with_multiple_keys VALUES(9,21,'a');
      gaussdb=# INSERT INTO range_sales_with_multiple_keys VALUES(10,5,'a');
      gaussdb=# INSERT INTO range_sales_with_multiple_keys VALUES(10,15,'a');
      gaussdb=# INSERT INTO range_sales_with_multiple_keys VALUES(10,20,'a');
      gaussdb=# INSERT INTO range_sales_with_multiple_keys VALUES(10,21,'a');
      gaussdb=# INSERT INTO range_sales_with_multiple_keys VALUES(11,5,'a');
      gaussdb=# INSERT INTO range_sales_with_multiple_keys VALUES(11,20,'a');
      gaussdb=# INSERT INTO range_sales_with_multiple_keys VALUES(11,21,'a');
      
      gaussdb=# SELECT * FROM range_sales_with_multiple_keys PARTITION (p1);
       c1 | c2 | c3
      ----+----+----
        9 |  5 | a
        9 | 20 | a
        9 | 21 | a
       10 |  5 | a
      (4 rows)
      
      gaussdb=# SELECT * FROM range_sales_with_multiple_keys PARTITION (p2);
       c1 | c2 | c3
      ----+----+----
       10 | 15 | a
      (1 row)
      
      gaussdb=# SELECT * FROM range_sales_with_multiple_keys PARTITION (p3);
       c1 | c2 | c3
      ----+----+----
       10 | 20 | a
       10 | 21 | a
       11 |  5 | a
       11 | 20 | a
       11 | 21 | a
      (5 rows)
      
      gaussdb=# DROP TABLE range_sales_with_multiple_keys;
      The partitioning rules for multi-column partition keys are as follows:
      1. The comparison starts from the first column.
      2. If the value of the inserted first column is smaller than the boundary value of the current column in the target partition, the values are directly inserted.
      3. If the value of the inserted first column is equal to the boundary of the current column in the target partition, compare the value of the inserted second column with the boundary of the next column in the target partition.
      4. If the value of the inserted first column is greater than the boundary of the current column in the target partition, compare the value with that in the next partition.
  2. START END

    If the START END clause is used, a range partitioning policy supports only a one-column partition key.

    Example:
    -- Create a tablespace.
    gaussdb=# CREATE TABLESPACE startend_tbs1 LOCATION '/home/omm/startend_tbs1';
    gaussdb=# CREATE TABLESPACE startend_tbs2 LOCATION '/home/omm/startend_tbs2';
    gaussdb=# CREATE TABLESPACE startend_tbs3 LOCATION '/home/omm/startend_tbs3';
    gaussdb=# CREATE TABLESPACE startend_tbs4 LOCATION '/home/omm/startend_tbs4';
    -- Create a temporary schema.
    gaussdb=# CREATE SCHEMA tpcds;
    gaussdb=# SET CURRENT_SCHEMA TO tpcds;
    -- Create a partitioned table with the partition key of the integer type.
    gaussdb=# CREATE TABLE tpcds.startend_pt (c1 INT, c2 INT)
    TABLESPACE startend_tbs1
    PARTITION BY RANGE (c2) (
        PARTITION p1 START(1) END(1000) EVERY(200) TABLESPACE startend_tbs2,
        PARTITION p2 END(2000),
        PARTITION p3 START(2000) END(2500) TABLESPACE startend_tbs3,
        PARTITION p4 START(2500),
        PARTITION p5 START(3000) END(5000) EVERY(1000) TABLESPACE startend_tbs4
    )
    ENABLE ROW MOVEMENT;
    
    -- View the information of the partitioned table.
    gaussdb=# SELECT relname, boundaries, spcname FROM pg_partition p JOIN pg_tablespace t ON
        p.reltablespace=t.oid and p.parentid='tpcds.startend_pt'::regclass ORDER BY 1;
    relname | boundaries | spcname
    -------------+------------+---------------
    p1_0 | {1} | startend_tbs2
    p1_1 | {201} | startend_tbs2
    p1_2 | {401} | startend_tbs2
    p1_3 | {601} | startend_tbs2
    p1_4 | {801} | startend_tbs2
    p1_5 | {1000} | startend_tbs2
    p2 | {2000} | startend_tbs1
    p3 | {2500} | startend_tbs3
    p4 | {3000} | startend_tbs1
    p5_1 | {4000} | startend_tbs4
    p5_2 | {5000} | startend_tbs4
    startend_pt | | startend_tbs1
    (12 rows)