表达式分区
支持指定基本表达式/函数作为分区键,且可通过指定的分区键进行创建和使用分区表,对于创建的分区表,支持分区表中的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;