跳转至

3.7.3 动态分区

开启动态分区的表,将会按照设定的规则添加、删除分区,从而对表的分区实现生命周期管理( TTL ),减少用户的使用负担。

动态分区只支持在 DATE/DATETIME 列上进行 Range 类型的分区。

动态分区适用于分区列的时间数据随现实世界同步增长的情况。此时可以灵活的按照与现实世界同步的时间维度对数据进行分区。

对于更为灵活,适用场景更多的数据入库分区,请参阅自动分区功能。

Warning

注意:动态分区功能在被 CCR 同步时将会失效。

如果这个表是被 CCR 复制而来的,即 PROPERTIES 中包含 is_being_synced = true 时,在 show create table 中会显示开启状态,但不会实际生效。当 is_being_synced 被设置为 false 时,这些功能将会恢复生效,但 is_being_synced 属性仅供 CCR 外围模块使用,在 CCR 同步的过程中不要手动设置。

1 使用方式

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

  • 建表时指定

    SQL
    1
    2
    3
    4
    5
    6
    7
    8
    CREATE TABLE tbl1
    (...)
    PROPERTIES
    (
        "dynamic_partition.prop1" = "value1",
        "dynamic_partition.prop2" = "value2",
        ...
    )
    
  • 运行时修改

    SQL
    1
    2
    3
    4
    5
    6
    ALTER TABLE tbl1 SET
    (
        "dynamic_partition.prop1" = "value1",
        "dynamic_partition.prop2" = "value2",
        ...
    )
    

2 规则参数

动态分区的规则参数都以 dynamic_partition. 为前缀:

  • dynamic_partition.enable

    是否开启动态分区特性。可指定为 TRUEFALSE 。如果不填写,默认为 TRUE 。如果为 FALSE ,则 Doris 会忽略该表的动态分区规则。

  • dynamic_partition.time_unit (必选参数)

    动态分区调度的单位。可指定为 HOURDAYWEEKMONTHYEAR 。分别表示按小时、按天、按星期、按月、按年进行分区创建或删除。

    当指定为 HOUR 时,动态创建的分区名后缀格式为 yyyyMMddHH ,例如 2020032501 。小时为单位的分区列数据类型不能为 DATE

    当指定为 DAY 时,动态创建的分区名后缀格式为 yyyyMMdd ,例如 20200325

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

    当指定为 MONTH 时,动态创建的分区名后缀格式为 yyyyMM ,例如 202003

    当指定为 YEAR 时,动态创建的分区名后缀格式为 yyyy ,例如 2020

  • dynamic_partition.time_zone

    动态分区的时区,如果不填写,则默认为当前机器的系统的时区,例如 Asia/Shanghai ,如果想获取当前支持的时区设置,可以参考https://en.wikipedia.org/wiki/List_of_tz_database_time_zones

  • dynamic_partition.start

    动态分区的起始偏移,为负数。根据 time_unit 属性的不同,以当天(星期或月)为基准,分区范围在此偏移之前的分区将会被删除。如果不填写,则默认为 -2147483648 ,即不删除历史分区。此偏移之后至当前时间的历史分区如不存在,是否创建取决于 dynamic_partition.create_history_partition

    Warning

    注意,若用户设置了 history_partition_num(>0) ,创建动态分区的起始分区就会用 max(start, -history_partition_num) ,删除历史分区的时候仍然会保留到 start 的范围,其中 start < 0

  • dynamic_partition.end (必选参数)

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

  • dynamic_partition.prefix (必选参数)

    动态创建的分区名前缀。

  • dynamic_partition.buckets

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

  • dynamic_partition.replication_num

    动态创建的分区所对应的副本数量,如果不填写,则默认为该表创建时指定的副本数量。

  • dynamic_partition.start_day_of_week

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

  • dynamic_partition.start_day_of_month

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

  • doris 支持 SSDHDD 层级存储,可参考分层存储

  • dynamic_partition.create_history_partition

    默认为 false 。当置为 true 时, Doris 会自动创建所有分区,具体创建规则见下文。同时, FE 的参数 max_dynamic_partition_num 会限制总分区数量,以避免一次性创建过多分区。当期望创建的分区个数大于 max_dynamic_partition_num 值时,操作将被禁止。

    当不指定 start 属性时,该参数不生效。

  • dynamic_partition.history_partition_num

    create_history_partitiontrue 时,该参数用于指定创建历史分区数量。默认值为 -1 ,即未设置。该变量与 dynamic_partition.start 作用相同,建议同时只设置一个。

  • dynamic_partition.reserved_history_periods

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

    举例说明。假设今天是 2021-09-06 ,按天分类,动态分区的属性设置为:

    time_unit="DAY/WEEK/MONTH/YEAR", end=3, start=-3, reserved_history_periods="[2020-06-01,2020-06-20],[2020-10-31,2020-11-15]"

    则系统会自动保留:

    SQL
    1
    2
    ["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]"

    则系统会自动保留:

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

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

3 创建历史分区规则

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

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

  • create_history_partition = true

    dynamic_partition.history_partition_num 未设置,即 -1expect_create_partition_num = end - start;

    dynamic_partition.history_partition_num 已设置 expect_create_partition_num = end - max(start, -histoty_partition_num);

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

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

举例说明:

假设今天是 2021-05-20 ,按天分区,动态分区的属性设置为, create_history_partition=true, end=3, start=-3 ,则会根据 history_partition_num 的设置,举例如下。

  • history_partition_num=1 ,则系统会自动创建以下分区:

    SQL
    1
    2
    3
    4
    5
    p20210519
    p20210520
    p20210521
    p20210522
    p20210523
    
  • history_partition_num=5 ,则系统会自动创建以下分区:

    SQL
    1
    2
    3
    4
    5
    6
    7
    p20210517
    p20210518
    p20210519
    p20210520
    p20210521
    p20210522
    p20210523
    
  • history_partition_num=-1 即不设置历史分区数量,则系统会自动创建以下分区:

    SQL
    1
    2
    3
    4
    5
    6
    7
    p20210517
    p20210518
    p20210519
    p20210520
    p20210521
    p20210522
    p20210523
    

4 示例

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

    SQL
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    CREATE TABLE tbl1
    (
        k1 DATE,
        ...
    )
    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.buckets" = "32"
    );
    

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

    SQL
    1
    2
    3
    4
    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

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

    SQL
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    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.buckets" = "8"
    );
    

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

    SQL
    1
    2
    3
    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" ,即以每周三为起始日。则分区如下:

    SQL
    1
    2
    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")
    

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

    Warning

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

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

    SQL
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    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.buckets" = "8",
        "dynamic_partition.start_day_of_month" = "3"
    );
    

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

    SQL
    1
    2
    3
    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 号为起始日,则分区范围为:

    SQL
    1
    2
    3
    p202004: ["2020-04-28", "2020-05-28")
    p202005: ["2020-05-28", "2020-06-28")
    p202006: ["2020-06-28", "2020-07-28")
    

5 原理与控制行为

Doris FE 中有固定的 dynamic partition 控制线程,持续以特定时间间隔(即 dynamic_partition_check_interval_seconds )进行 dynamic partition 表的分区检查,完成需要的分区创建与删除操作。

具体而言,自动分区将会进行如下检查与操作(我们称此时该表分区的起始包含时间为 START ,末尾包含时间为 END ,省略 propertydynamic_partition. 前缀):

  1. START 时间之前的所有分区,全部被删除。

  2. 如果 create_history_partitionfalse ,创建当前时间到 END 之间的所有分区;如果 create_history_partitiontrue ,除当前时间到 END 之间的分区外,还会创建 START 到当前时间的分区。若定义了 history_partition_num ,则从当前时间向前创建的分区数量不超过 history_partition_num

需要注意的是:

  1. 如果分区时间范围与 [START, END] 范围相交,则认为属于当前 dynamic partition 时间范围。

  2. 如果尝试创建的新分区和现有分区冲突,则保留当前分区,不创建该新分区。如果该行为出现在建表时, DDL 将会报错。

因此,自动分区表在系统自动维护后,呈现的状态是:

  1. START 时间之前,除 reserved_history_periods 所指定范围以外,不包含任何分区;

  2. END 时间之后,保留所有手动创建的分区。

  3. 除手动删除或意外丢失的分区外,表包含特定范围内的全部分区:

    1. 如果 create_history_partitiontrue

      1. 若定义了 history_partition_num ,则特定范围为 [max(START, 当前时间 - history_partition_num * time_unit), END]

      2. 若未定义 history_partition_num ,则特定范围为 [START, END]

    2. 如果 create_history_partitionfalse ,则特定范围为 [当前时间, END] ,同时包含 [START, 当前时间) 中既存的分区。

    整个特定范围按照 time_unit 划分为若干分区范围。对于任意一个范围,如果其与某个当前存在的分区 X 相交,则 X 被保留,否则该范围将被 dynamic partition 所创建的一个分区所完整覆盖。

  4. 除非分区数量即将超过 max_dynamic_partition_num ,创建将会失败。

6 修改动态分区属性

通过如下命令可以修改动态分区的属性:

SQL
1
2
3
4
5
ALTER TABLE tbl1 SET
(
    "dynamic_partition.prop1" = "value1",
    ...
);

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

SQL
1
2
3
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-222020-05-30 时间段的分区,需要自行填补。

7 查看动态分区表调度情况

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

SQL
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
> 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 :最后一次执行动态删除分区调度的错误信息

8 高级操作

FE 配置项

  • dynamic_partition_enable

    是否开启 Doris 的动态分区功能。默认为 false ,即关闭。该参数只影响动态分区表的分区操作,不影响普通表。可以通过修改 fe.conf 中的参数并重启 FE 生效。也可以在运行时执行以下命令生效:

    SQL
    1
    2
    3
    4
    5
    # MySQL 协议
    ADMIN SET FRONTEND CONFIG ("dynamic_partition_enable" = "true")
    
    # HTTP 协议
    curl --location-trusted -u username:password -XGET http://fe_host:fe_http_port/api/_set_config?dynamic_partition_enable=true
    

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

  • dynamic_partition_check_interval_seconds

    动态分区线程的执行频率,默认为 60010 分钟),即每 10 分钟进行一次调度。可以通过修改 fe.conf 中的参数并重启 FE 生效。也可以在运行时执行以下命令修改:

    SQL
    1
    2
    3
    4
    5
    # MySQL 协议
    ADMIN SET FRONTEND CONFIG ("dynamic_partition_check_interval_seconds" = "7200")
    
    # HTTP 协议
    curl --location-trusted -u username:password -XGET http://fe_host:fe_http_port/api/_set_config?dynamic_partition_check_interval_seconds=432000
    

动态分区表与手动分区表相互转换

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

通过执行 ALTER TABLE tbl_name SET ("dynamic_partition.enable" = "<true/false>") 即可调整动态分区开关状态。

关闭动态分区功能后, Doris 将不再自动管理分区,需要用户手动通过 ALTER TABLE 的方式创建或删除分区。动态分区开启后,可能立即根据动态分区规则清理多余分区。