动态分区

本文介绍云数据库 SelectDB 版动态分区相关的概念和示例,帮助您进行分区的动态管理,降低您的使用成本。

概述

在某些场景下,可能会将数据库表按照天进行分区划分。如果需要手动管理分区,可能由于没有创建分区导致数据导入失败,这给数据库管理人员带来了额外的维护成本。通过动态分区功能,可以在建表时设定动态分区规则。云数据库 SelectDB 版根据指定的规则创建或删除分区,也可以在运行时对现有规则进行变更,从而进行分区管理。

说明

目前云数据库SelectDB版动态分区只支持Range分区且实现了动态添加、删除分区的功能。

创建动态分区表

动态分区的规则可以在建表时指定,或者在运行时进行修改。当前仅支持对单分区列的分区表设定动态分区规则。建表时指定动态分区规则的语法如下。

CREATE TABLE tbl1
(...)
PROPERTIES
( 
	"dynamic_partition.prop1" = "value1",
 	"dynamic_partition.prop2" = "value2",
  ...
)

全局配置项

以下与动态分区相关的配置影响整个SelectDB实例环境。

  • dynamic_partition_enable

    是否开启动态分区功能,默认为true。该参数只影响动态分区表的分区操作,不影响普通表。

    可以在运行时执行如下命令生效。

    ADMIN SET FRONTEND CONFIG ("dynamic_partition_enable" = "true")

    若要全局关闭动态分区,则设置此参数为false即可。

  • dynamic_partition_check_interval_seconds

    动态分区线程的执行频率,默认为600(10分钟),即每10分钟进行一次调度,自动创建动态分区。

    可以在运行时执行如下命令修改。

    ADMIN SET FRONTEND CONFIG ("dynamic_partition_check_interval_seconds" = "7200")

表配置项

动态分区的规则参数都以dynamic_partition.为前缀,动态分区相关的配置的详细说明如下。

参数名称

默认值

参数说明

dynamic_partition.enable

TRUE

是否开启动态分区特性。可指定为TRUEFALSE

  • TRUE:开启动态分区。

  • FALSE:则会忽略该表的动态分区规则。

dynamic_partition.time_unit

动态分区调度的单位。可指定为HOURDAYWEEKMONTH

  • HOUR表示按小时创建或删除分区,动态创建的分区名后缀格式为yyyyMMddHH,例如2020032501。小时为单位的分区列数据类型不能为 DATE。

  • DAY表示按天时创建或删除分区,动态创建的分区名后缀格式为yyyyMMdd,例如20200325

  • WEEK表示按星期创建或删除分区,动态创建的分区名后缀格式为yyyy_ww。即当前日期属于这一年的第几周,例如2020-03-25创建的分区名后缀为2020_13, 表明目前为2020年第13周。

  • MONTH表示按月创建或删除分区,动态创建的分区名后缀格式为yyyyMM,例如202003

dynamic_partition.time_zone

Asia/Shanghai

动态分区的时区。

dynamic_partition.start

-2147483648

动态分区的起始偏移,为负数。根据time_unit属性的不同,以当天(星期/月)为基准,分区范围在此偏移之前的分区将会被删除。默认值即不删除历史分区。

dynamic_partition.end

动态分区的结束偏移,为正数。根据time_unit属性的不同,以当天(星期/月)为基准,提前创建对应范围的分区。

dynamic_partition.prefix

动态创建的分区名前缀。

dynamic_partition.create_history_partition

false

创建历史分区规则。当不指定dynamic_partition.start属性时,该参数不生效。当置为true时,会自动创建所有分区,具体创建规则见下文历史分区创建规则。同时,FE的参数max_dynamic_partition_num会限制总分区数量,以避免一次性创建过多分区。当期望创建的分区个数大于max_dynamic_partition_num值时,操作将被禁止。

dynamic_partition.history_partition_num

-1

指定创建历史分区数量。当create_history_partitiontrue时,该参数用于指定创建历史分区数量。默认值即表时未设置。

dynamic_partition.reserved_history_periods

"NULL"

需要保留的历史分区的时间范围。当dynamic_partition.time_unit设置为 "DAY/WEEK/MONTH" 时,需要以[yyyy-MM-dd,yyyy-MM-dd],[...,...]格式进行设置。当dynamic_partition.time_unit设置为 "HOUR" 时,需要以[yyyy-MM-dd HH:mm:ss,yyyy-MM-dd HH:mm:ss],[...,...]的格式来进行设置。

dynamic_partition.buckets

动态创建的分区所对应的分桶数量。

dynamic_partition.start_day_of_week

1

指定每周的起始点。当time_unitWEEK时,该参数用于指定每周的起始点。取值为1到7。其中1表示周一,7表示周日。默认值即表示每周以周一为起始点。

dynamic_partition.start_day_of_month

1

指定每月的起始日期。当time_unitMONTH时,该参数用于指定每月的起始日期。取值为1到 28。其中1表示每月1号,28表示每月28号。暂不支持以29、30、31号为起始日,以避免因闰年或闰月带来的歧义。默认值即表示每月以1号位起始点。

dynamic_partition.reserved_history_periods相关参数示例如下

例如:按天分类。

  • 设置动态分区的属性为:time_unit="DAY/WEEK/MONTH", end=3, start=-3, reserved_history_periods="[2020-06-01,2020-06-20],[2020-10-31,2020-11-15]"

    则系统会自动保留:

    ["2020-06-01","2020-06-20"],["2020-10-31","2020-11-15"]
  • 设置动态分区的属性为:time_unit="HOUR", end=3, start=-3, reserved_history_periods="[2020-06-01 00:00:00,2020-06-01 03:00:00]"

    则系统会自动保留:

    ["2020-06-01 00:00:00","2020-06-01 03:00:00"]

    这两个时间段的分区。其中,reserved_history_periods的每一个[...,...]是一对设置项,两者需要同时被设置,且第一个时间不能大于第二个时间。

历史分区创建规则

create_history_partitionTRUE,即开启创建历史分区功能时,SelectDB会根据dynamic_partition.startdynamic_partition.history_partition_num来决定创建历史分区的个数。

例如:需要创建的历史分区数量为expect_create_partition_num,根据不同的设置具体数量如下。

  • create_history_partition=true

    • dynamic_partition.history_partition_num未设置,即-1。则expect_create_partition_num=end-start

    • dynamic_partition.history_partition_num已设置,则expect_create_partition_num=end-Max(start,-history_partition_num)

  • create_history_partition=false不会创建历史分区,则expect_create_partition_num=end-0

说明

expect_create_partition_num大于max_dynamic_partition_num(默认500)时,禁止创建过多分区。

历史分区示例

  1. 例如:今天是2021-05-20,按天分区,动态分区的属性设置为:create_history_partition=true, end=3, start=-3, history_partition_num=1,则系统会自动创建以下分区。

    p20210519
    p20210520
    p20210521
    p20210522
    p20210523
  2. 例如:今天是2021-05-20,按天分区,动态分区的属性设置为:create_history_partition=true, end=3, start=-3, history_partition_num=5,则系统会自动创建以下分区。

    p20210517
    p20210518
    p20210519
    p20210520
    p20210521
    p20210522
    p20210523
  3. 例如:今天是2021-05-20,按天分区,动态分区的属性设置为:create_history_partition=true, end=3, start=-3, history_partition_num=-1即不设置历史分区数量,则系统会自动创建以下分区。

    p20210517
    p20210518
    p20210519
    p20210520
    p20210521
    p20210522
    p20210523
    重要

    动态分区使用过程中,如果因为一些意外情况导致dynamic_partition.startdynamic_partition.end之间的某些分区丢失,那么当前时间与dynamic_partition.end之间的丢失分区会被重新创建,dynamic_partition.start与当前时间之间的丢失分区不会重新创建。

使用示例

  • tbl1分区列k1类型为DATE,创建一个动态分区规则。按天分区,只保留最近7天的分区,并且预先创建未来3天的分区。

    CREATE TABLE tbl1
    (
    	k1 DATE,
    	k2 int
    )
    PARTITION BY RANGE(k1) ()
    DISTRIBUTED BY HASH(k1)
    PROPERTIES
    (
    	"dynamic_partition.enable" = "true",
    	"dynamic_partition.time_unit" = "DAY",
    	"dynamic_partition.start" = "-7",
    	"dynamic_partition.end" = "3",
    	"dynamic_partition.prefix" = "p",
    	"dynamic_partition.create_history_partition" = "true",
    	"dynamic_partition.buckets" = "32"
    );

    例如:当前日期为2020-05-29。则根据以上规则,表tbl1会产生以下分区:

    p20200529: ["2020-05-29", "2020-05-30")
    p20200530: ["2020-05-30", "2020-05-31")
    p20200531: ["2020-05-31", "2020-06-01")
    p20200601: ["2020-06-01", "2020-06-02")

    在第二天,即2020-05-30,会创建新的分区p20200602: ["2020-06-02", "2020-06-03")

    在2020-06-06时,因为dynamic_partition.start设置为7,则将删除7天前的分区,即删除分区p20200529

  • tbl1分区列k1类型为DATETIME,创建一个动态分区规则。按星期分区,只保留最近2个星期的分区,并且预先创建未来2个星期的分区。

    CREATE TABLE tbl1
    (
    	k1 DATETIME,
      ...
    )
    PARTITION BY RANGE(k1) ()
    DISTRIBUTED BY HASH(k1)
    PROPERTIES
    (	
    	"dynamic_partition.enable" = "true",
    	"dynamic_partition.time_unit" = "WEEK",
    	"dynamic_partition.start" = "-2",
    	"dynamic_partition.end" = "2",
    	"dynamic_partition.prefix" = "p",
    	"dynamic_partition.create_history_partition" = "true",
    	"dynamic_partition.buckets" = "8"
    );

    例如:当前日期为2020-05-29,是2020年的第22周。默认每周起始为星期一。则基于以上规则,表tbl1 会产生以下分区:

    p2020_22: ["2020-05-25 00:00:00", "2020-06-01 00:00:00")
    p2020_23: ["2020-06-01 00:00:00", "2020-06-08 00:00:00")
    p2020_24: ["2020-06-08 00:00:00", "2020-06-15 00:00:00")

    其中每个分区的起始日期为该周的周一。同时,因为分区列k1的类型为DATETIME,则分区值会补全时分秒部分,且皆为0。

    在2020-06-15,即第25周时,会删除2周前的分区,即删除p2020_22

    在上面的例子中,例如指定了周起始日为"dynamic_partition.start_day_of_week" = "3",即以每周三为起始日。则分区如下:

    p2020_22: ["2020-05-27 00:00:00", "2020-06-03 00:00:00")
    p2020_23: ["2020-06-03 00:00:00", "2020-06-10 00:00:00")
    p2020_24: ["2020-06-10 00:00:00", "2020-06-17 00:00:00")

    即分区范围为当周的周三到下周的周二。

    说明

    2019-12-31 和 2020-01-01 在同一周内,如果分区的起始日期为 2019-12-31,则分区名为p2019_53,如果分区的起始日期为 2020-01-01,则分区名为p2020_01

  • tbl1分区列k1类型为DATE,创建一个动态分区规则。按月分区,不删除历史分区,并且预先创建未来2个月的分区。同时设定以每月3号为起始日。

    CREATE TABLE tbl1
    (
    	k1 DATE,
      ...
    )
    PARTITION BY RANGE(k1) ()
    DISTRIBUTED BY HASH(k1)
    PROPERTIES
    (
    	"dynamic_partition.enable" = "true",
    	"dynamic_partition.time_unit" = "MONTH",
    	"dynamic_partition.end" = "2",
    	"dynamic_partition.prefix" = "p",
    	"dynamic_partition.create_history_partition" = "true",
            "dynamic_partition.history_partition_num" = "6",
    	"dynamic_partition.buckets" = "8",
    	"dynamic_partition.start_day_of_month" = "3"
    );

    例如:当前日期为2020-05-29。则基于以上规则,表tbl1会产生以下分区:

    p202005: ["2020-05-03", "2020-06-03")
    p202006: ["2020-06-03", "2020-07-03")
    p202007: ["2020-07-03", "2020-08-03")

    因为没有设置dynamic_partition.start,则不会删除历史分区。

    例如:今天为2020-05-20,并设置以每月28号为起始日,则分区范围为:

    p202004: ["2020-04-28", "2020-05-28")
    p202005: ["2020-05-28", "2020-06-28")
    p202006: ["2020-06-28", "2020-07-28")

修改动态分区属性

通过如下命令,可以在运行时修改动态分区的属性。

ALTER TABLE tbl1 SET( "dynamic_partition.prop1" = "value1", ...);

某些属性的修改可能会产生冲突。假设之前分区粒度为DAY,并且已经创建了如下分区。

p20200519: ["2020-05-19", "2020-05-20")
p20200520: ["2020-05-20", "2020-05-21")
p20200521: ["2020-05-21", "2020-05-22")

如果此时将分区粒度改为MONTH,则系统会尝试创建范围为["2020-05-01", "2020-06-01")的分区,而该分区的分区范围和已有分区冲突,所以无法创建。而范围为["2020-06-01", "2020-07-01")的分区可以正常创建。因此,2020-05-22到2020-05-30时间段的分区,需要自行填补。

删除动态分区表的分区

删除动态分区表的分区,要求提前通过如下命令,关闭动态分区属性。

ALTER TABLE tbl1 SET ("dynamic_partition.enable" = "false");

然后在通过如下命令,删除某个指定的分区。

ALTER TABLE tbl1 DROP PARTITION p20200519;

通常动态分区表的分区删除后,需要重新打开动态分区属性,以便后续业务运行过程中,仍由数仓系统自动管理分区。

ALTER TABLE tbl1 SET ("dynamic_partition.enable" = "true");

查看动态分区表调度情况

通过以下命令可以进一步查看当前数据库下,所有动态分区表的调度情况。

mysql> SHOW DYNAMIC PARTITION TABLES;
+-----------+--------+----------+-------------+------+--------+---------+-----------+----------------+---------------------+--------+------------------------+----------------------+-------------------------+
| TableName | Enable | TimeUnit | Start       | End  | Prefix | Buckets | StartOf   | LastUpdateTime | LastSchedulerTime   | State  | LastCreatePartitionMsg | LastDropPartitionMsg | ReservedHistoryPeriods  |
+-----------+--------+----------+-------------+------+--------+---------+-----------+----------------+---------------------+--------+------------------------+----------------------+-------------------------+
| d3        | true   | WEEK     | -3          | 3    | p      | 1       | MONDAY    | N/A            | 2020-05-25 14:29:24 | NORMAL | N/A                    | N/A                  | [2021-12-01,2021-12-31] |
| d5        | true   | DAY      | -7          | 3    | p      | 32      | N/A       | N/A            | 2020-05-25 14:29:24 | NORMAL | N/A                    | N/A                  | NULL                    |
| d4        | true   | WEEK     | -3          | 3    | p      | 1       | WEDNESDAY | N/A            | 2020-05-25 14:29:24 | NORMAL | N/A                    | N/A                  | NULL                    | 
| d6        | true   | MONTH    | -2147483648 | 2    | p      | 8       | 3rd       | N/A            | 2020-05-25 14:29:24 | NORMAL | N/A                    | N/A                  | NULL                    |
| d2        | true   | DAY      | -3          | 3    | p      | 32      | N/A       | N/A            | 2020-05-25 14:29:24 | NORMAL | N/A                    | N/A                  | NULL                    |
| d7        | true   | MONTH    | -2147483648 | 5    | p      | 8       | 24th      | N/A            | 2020-05-25 14:29:24 | NORMAL | N/A                    | N/A                  | NULL                    |
+-----------+--------+----------+-------------+------+--------+---------+-----------+----------------+---------------------+--------+------------------------+----------------------+-------------------------+
7 rows in set (0.02 sec)
  • LastUpdateTime: 最后一次修改动态分区属性的时间。

  • LastSchedulerTime: 最后一次执行动态分区调度的时间。

  • State: 最后一次执行动态分区调度的状态。

  • LastCreatePartitionMsg: 最后一次执行动态添加分区调度的错误信息。

  • LastDropPartitionMsg: 最后一次执行动态删除分区调度的错误信息。

高级操作

对于一个表来说,动态分区和手动分区可以自由转换,但二者不能同时存在,只能有一种状态。

手动分区转换为动态分区

如果一个表在创建时未指定动态分区,可以通过ALTER TABLE在运行时修改动态分区相关属性来转化为动态分区。

开启动态分区功能后,将不再允许手动管理分区,会根据动态分区属性来自动管理分区。

重要

如果已设定dynamic_partition.start,分区范围在动态分区起始偏移之前的历史分区将会被删除。

动态分区转换为手动分区

通过执行ALTER TABLE tbl_name SET ("dynamic_partition.enable" = "false")即可关闭动态分区功能,将其转换为手动分区表。

关闭动态分区功能后,将不再自动管理分区,需要手动通过ALTER TABLE方式创建或删除分区。

常见问题

  • Q:创建动态分区表时提示“Could not create table with dynamic partition when fe config dynamic_partition_enable is false

    A:由于动态分区的全局开关dynamic_partition_enable为false,导致无法创建动态分区表。执行命令ADMIN SET FRONTEND CONFIG ("dynamic_partition_enable" = "true")将动态分区开关打开即可。

  • Q:关于动态分区的副本设置

    A:动态分区是由系统内部的调度逻辑自动创建的。在自动创建分区时,所使用的分区属性(包括分区的副本数等),都是单独使用dynamic_partition前缀的属性,而不是使用表的默认属性。示例如下。

    CREATE TABLE tbl1 (
    `k1` int,
    `k2` date
    )
    PARTITION BY RANGE(k2)()
    DISTRIBUTED BY HASH(k1) BUCKETS 3
    PROPERTIES
    (
    	"dynamic_partition.enable" = "true",
    	"dynamic_partition.time_unit" = "DAY",
    	"dynamic_partition.start" = "-3",
    	"dynamic_partition.end" = "3",
    	"dynamic_partition.prefix" = "p",
    	"dynamic_partition.create_history_partition" = "true",
    	"dynamic_partition.buckets" = "32"
    );

    上述示例中,没有创建任何初始分区(PARTITION BY子句中的分区定义为空),并且设置了DISTRIBUTED BY HASH(k1) BUCKETS 3"dynamic_partition.buckets" = "32"

    前一个参数将成为表的默认参数,而后一个参数成为动态分区专用参数。当系统自动创建分区时,会使用分桶数32(即动态分区专用参数),而不是分桶数3。当通过ALTER TABLE tbl1 ADD PARTITION语句手动添加分区时,则会使用分桶数3(即表的默认参数)。即动态分区使用一套独立的参数设置,只有当没有设置动态分区专用参数时,才会使用表的默认参数。

    CREATE TABLE tbl3 (
    `k1` int,
    `k2` date
    )
    PARTITION BY RANGE(k2)(
    	PARTITION p1 VALUES LESS THAN ("2019-10-10")
    )
    DISTRIBUTED BY HASH(k1) BUCKETS 3
    PROPERTIES
    (
    	"dynamic_partition.enable" = "true",
    	"dynamic_partition.time_unit" = "DAY",
    	"dynamic_partition.start" = "-3",
    	"dynamic_partition.end" = "3",
    	"dynamic_partition.prefix" = "p",
            "dynamic_partition.create_history_partition" = "true",
    	"dynamic_partition.buckets" = "32"
    );

    这个示例中,有一个手动创建的分区p1。这个分区会使用表的默认设置,即分桶数3。而后续系统自动创建的动态分区,依然会使用动态分区专用参数,即分桶数32。