更新时间:2026-07-28 GMT+08:00
分享

表达式分区

支持指定基本表达式/函数作为分区键,且可通过指定的分区键进行创建和使用分区表,对于创建的分区表,支持分区表中的DDL功能和DML功能,实现查询优化和运维管理。

  • 表达式分区仅在M-Compatibility模式数据库中生效。
  • 支持在分区表的分区键中使用表达式,数据分布方式根据表达式的计算结果进行分区,其他使用方式和非表达式分区表一致。
  • 表达式分区对于一级分区支持范围分区、哈希分区以及列表分区,二级分区支持Range-Hash以及List-Hash分区。
  • 表达式分区中分区键的个数仅支持1个。
  • 表达式中不支持包含生成列。
  • 表达式分区键中支持函数和操作符如表1所示。
    表1 支持作为表达式分区键的函数和操作符

    函数

    ABS()

    CEILING()

    对应分区场景下函数返回值类型需要满足该分区的数据类型约束。

    DATEDIFF()

    DAY()

    DAYOFMONTH()

    DAYOFWEEK()

    DAYOFYEAR()

    EXTRACT()

    不支持使用week标识符。

    FLOOR()

    对应分区场景下函数返回值类型需要满足该分区的数据类型约束。

    HOUR()

    MICROSECOND()

    MINUTE()

    MOD()

    MONTH()

    QUARTER()

    SECOND()

    TIME_TO_SEC()

    TO_DAYS()

    TO_SECONDS()

    UNIX_TIMESTAMP()

    只支持TIMESTAMP类型的列。

    WEEKDAY()

    YEAR()

    YEARWEEK()

    -

    操作符

    DIV 操作符

    + 操作符

    - 操作符

    进行减操作。

    - 操作符

    进行取负操作。

    * 操作符

    -

    表达式的计算结果需要满足对应分区的数据类型约束。例如:CEILING(float)返回值为float类型,该表达式使用在range分区会因为数据类型不支持而报错。CEILING(int)返回值为int类型,则可以直接在range分区使用。

示例

  • 范围表达式分区,示例如下:
    -- 通过order_time将订单按时间的月份划分为上半年订单和下半年订单,分别存储到对应的分区中。
    m_db=# CREATE TABLE range_expr_part(order_id INT, order_time DATETIME)
    PARTITION BY RANGE(MONTH(order_time))
    (
       PARTITION p_first_half VALUES LESS THAN(7),
       PARTITION p_second_half VALUES LESS THAN(13)
    );
    m_db=# DROP TABLE range_expr_part;
  • 哈希表达式分区,示例如下:
    -- 通过order_time字段将订单按时间中的年份通过hash计算划分到5个分区,分别存储到对应的分区中。
    m_db=# CREATE TABLE hash_expr_part(order_id INT, order_time DATETIME)
    PARTITION by HASH(YEAR(order_time))
    (
       PARTITION p_0,
       PARTITION p_1,
       PARTITION p_2,
       PARTITION p_3,
       PARTITION p_4
    );
    m_db=# DROP TABLE hash_expr_part;
  • 列表表达式分区,示例如下:
    -- 通过order_time字段将订单按时间中的月份通过根据具体分区枚举信息,将订单划分到4个季度,分别存储到对应的分区中。
    m_db# CREATE TABLE list_expr_part(order_id INT, order_time DATETIME)
    PARTITION BY LIST(MONTH(order_time))
    (
       PARTITION p_first_quarter VALUES (1, 2, 3),
       PARTITION p_second_quarter VALUES (4, 5, 6),
       PARTITION p_third_quarter VALUES (7, 8, 9),
       PARTITION p_fourth_quarter VALUES (10, 11, 12)
    );
    m_db=# DROP TABLE list_expr_part;
  • range-hash表达式分区,示例如下:
    m_db=# CREATE TABLE range_hash_expr_part
    (
        a INT,
        b INT,
        c CHAR(24)
    )
    PARTITION BY RANGE (abs(a)) SUBPARTITION BY HASH (MOD(a, 10))
    (
      PARTITION p50 VALUES LESS THAN(50)
      (
        SUBPARTITION p50_a,
        SUBPARTITION p50_b
      ),
      PARTITION p100 VALUES LESS THAN(100)
      (
        SUBPARTITION p100_a,
        SUBPARTITION p100_b
      )
    );
    m_db=# DROP TABLE range_hash_expr_part;
  • list-hash分区表达式分区,示例如下:
    m_db=# CREATE TABLE list_hash_expr_part
    (
        a INT,
        b DATETIME,
        c CHAR(24)
    )
    PARTITION BY LIST (a DIV 10) SUBPARTITION BY HASH (QUARTER(b))
    (
      PARTITION list_small VALUES (0, 1, 2, 3, 4)
      (
        SUBPARTITION list_small_a,
        SUBPARTITION list_small_b
      ),
      PARTITION list_large VALUES (5, 6, 7, 8, 9)
      (
        SUBPARTITION list_large_a,
        SUBPARTITION list_large_b
      ),
      PARTITION list_default VALUES (default)
      (
        SUBPARTITION list_default_a,
        SUBPARTITION list_default_b
      )
    );
    m_db=# DROP TABLE list_hash_expr_part;
  • 表达式分区表静态剪枝,示例如下:
    -- 在满足剪枝当前已有的条件下,还需要检索条件中的表达式信息和分区键完全匹配,可以满足表达式分区场景下的静态剪枝。
    m_db=# CREATE TABLE expr_part (c1 int, c2 int)
        PARTITION BY RANGE (c1 + 1)
    (
        PARTITION p1 VALUES LESS THAN(10),
        PARTITION p2 VALUES LESS THAN(20),
        PARTITION p3 VALUES LESS THAN(MAXVALUE)
    );
    m_db=# EXPLAIN (VERBOSE ON, COSTS OFF) SELECT * FROM expr_part WHERE c1 + 1 = 1;
                    QUERY PLAN                
    ------------------------------------------
     Partitioned Seq Scan on public.expr_part
       Output: c1, c2
       Filter: ((expr_part.c1 + 1) = 1)
       Selected Partitions:  1
    (4 rows)
    m_db=# DROP TABLE expr_part;
  • 表达式分区表动态剪枝,示例如下:
    -- 在满足剪枝当前已有的条件下,还需要join条件中表达式完全匹配分区键表达式,且索引的信息也与分区键表达式完全相同,可以满足表达式分区场景下的动态剪枝。
    m_db=# CREATE TABLE expr_part1 (c1 int, c2 int)
        PARTITION BY RANGE (c1 + 1)
    (
        PARTITION p1 VALUES LESS THAN(10),
        PARTITION p2 VALUES LESS THAN(20),
        PARTITION p3 VALUES LESS THAN(MAXVALUE)
    );
    CREATE TABLE expr_part2 (c1 INT, c2 INT)
        PARTITION BY RANGE (c1 + 2)
    (
        PARTITION p1 VALUES LESS THAN(10),
        PARTITION p2 VALUES LESS THAN(20),
        PARTITION p3 VALUES LESS THAN(30),
        PARTITION p4 VALUES LESS THAN(MAXVALUE)
    );
    CREATE INDEX idx_expr_part1_c1 ON expr_part1((c1 + 1)) LOCAL;
    m_db=# EXPLAIN (VERBOSE ON, COSTS OFF) SELECT /*+ nestloop(t2 t1) */* FROM expr_part2 t2 JOIN expr_part1 t1 ON (t1.c1 + 1) = (t2.c2 + 2);
                                         QUERY PLAN                                     
    ------------------------------------------------------------------------------------
     Nested Loop
       Output: t2.c1, t2.c2, t1.c1, t1.c2
       ->  Partition Iterator
             Output: t2.c1, t2.c2
             Iterations: 4
             ->  Partitioned Seq Scan on public.expr_part2 t2
                   Output: t2.c1, t2.c2
                   Selected Partitions:  1..4
       ->  Partition Iterator
             Output: t1.c1, t1.c2
             Iterations: PART
             ->  Partitioned Index Scan using idx_expr_part1_c1 on public.expr_part1 t1
                   Output: t1.c1, t1.c2
                   Index Cond: ((t1.c1 + 1) = (t2.c2 + 2))
                   Selected Partitions:  1..3 (ppi-pruning)
    (15 rows)
    m_db=# DROP TABLE expr_part1;
    m_db=# DROP TABLE expr_part2;

相关文档