动态分区管理

Hologres的动态分区功能无需预先设定所有分区信息,可依据创建分区表时配置的动态分区规则,自动创建并管理分区子表。同时,还支持将符合条件的分区数据迁移到低频存储设备,在保证查询性能的同时,有效降低存储费用。

功能介绍

动态分区功能各版本支持情况如下:

  • Hologres V1.3版本开始,支持配置动态分区规则,系统会根据已配置的规则定期运行调度任务,提前创建分区子表和删除过期分区子表。

  • Hologres V1.3.37版本开始,支持动态管理冷热数据分层存储,来实现数据自动降冷,降低存储成本,详情请参见数据分层存储

  • Holgores V2.1.11版本开始,动态分区支持Date类型做分区键。

  • Hologres V2.2版本开始,支持通过动态分区配置表中的schd_start_time属性来自定义分区调度时间,即自定义设置分区表创建、删除、转冷的时间。

使用限制

  • Hologres暂不支持插入数据至分区表父表,只支持插入数据至具体的分区表子表。

    说明

    实时计算Flink版支持实时写入数据至Hologres的分区表父表,详情请参见实时写入数据至Hologres的分区结果表

  • 一个分区规则只能创建一个分区表。

  • PARTITION BY类型仅支持LIST分区,切分PARTITION BY LIST只能取唯一值。

  • 若是表有主键,分区键必须是主键的一个子集。

  • 动态分区能力仅支持对分区父表设置调度时间(schd_start_time),不支持对分区子表设置。

配置动态分区

语法说明

动态分区管理配置既支持在创建分区表时配置动态分区管理属性,也支持在建表后修改动态分区管理属性,语法如下所示。

  • V2.1版本起支持的语法:

    • 创建分区表时,配置动态分区管理属性

      -- 创建分区表时配置动态分区管理属性
      CREATE TABLE [if not exists] [<schema_name>.]<table_name>  ([
        {
         <column_name> <column_type> [ <column_constraints>, [...]]
         | <table_constraints>
         [, ...]
        }
      ])
      PARTITION BY LIST(<column_name>)
      WITH (
         auto_partitioning_enable = 'xxx',
         auto_partitioning_time_unit = 'xxx',
         auto_partitioning_time_zone = 'xxx',
         auto_partitioning_num_precreate = 'xxx',
         auto_partitioning_num_retention = 'xxx',
         auto_partitioning_num_hot='xxx',
         auto_partitioning_schd_start_time = 'xxx'
      );
    • 创建分区表后,修改动态分区管理属性

      -- 修改动态分区管理属性
      ALTER TABLE [<schema_name>.]<table_name> SET (
         auto_partitioning_enable = 'xxx',
         auto_partitioning_time_unit = 'xxx',
         auto_partitioning_time_zone = 'xxx',
         auto_partitioning_num_precreate = 'xxx',
         auto_partitioning_num_retention = 'xxx',
         auto_partitioning_num_hot='xxx',
         auto_partitioning_schd_start_time = 'xxx'
      );
      
  • 所有版本支持的语法:

    • 创建分区表时,配置动态分区管理属性

      -- 创建分区表时配置动态分区管理属性
      BEGIN;
      CREATE TABLE [if not exists] [<schema_name>.]<table_name>  ([
        {
         <column_name> <column_type> [ <column_constraints>, [...]]
         | <table_constraints>
         [, ...]
        }
      ])
      PARTITION BY LIST(<column_name>);
      CALL set_table_property('[<schema_name>.]<table_name>', 'auto_partitioning.enable', 'xxx');
      CALL set_table_property('[<schema_name>.]<table_name>', 'auto_partitioning.time_unit', 'xxx');
      CALL set_table_property('[<schema_name>.]<table_name>', 'auto_partitioning.time_zone', 'xxx');
      CALL set_table_property('[<schema_name>.]<table_name>', 'auto_partitioning.num_precreate', 'xxx');
      CALL set_table_property('[<schema_name>.]<table_name>', 'auto_partitioning.num_retention', 'xxx');
      CALL set_table_property('[<schema_name>.]<table_name>', 'auto_partitioning.num_retention', 'xxx');
      CALL set_table_property('[<schema_name>.]<table_name>', 'auto_partitioning.num_hot', 'xxx');
      CALL set_table_property ('[<schema_name>.]<table_name>', 'auto_partitioning.schd_start_time', 'xxx');
      COMMIT;
    • 创建分区表后,修改动态分区管理属性

      -- 修改动态分区管理属性
      CALL set_table_property('[<schema_name>.]<table_name>', 'auto_partitioning.enable', 'xxx');
      CALL set_table_property('[<schema_name>.]<table_name>', 'auto_partitioning.num_precreate', 'xxx');
      CALL set_table_property('[<schema_name>.]<table_name>', 'auto_partitioning.num_retention', 'xxx');

参数说明

重要

使用CREATE TABLE WITH语法配置动态分区时,需要将参数名中的.改为_。例如在Hologres V2.1版本中使用CREATE TABLE WITH语法配置动态分区时,auto_partitioning.enable参数名需改为auto_partitioning_enable

参数

是否必选

说明

是否可更新

auto_partitioning.enable

是否启用动态分区管理,取值说明如下:

  • true:启用动态分区管理。

  • false(默认值):关闭动态分区管理。

auto_partitioning.time_unit

动态分区的时间单位,取值说明如下:

  • HOUR

  • DAY

  • MONTH

  • QUARTER

  • YEAR

例如配置为DAY,则将按天进行分区的预创建、删除。

auto_partitioning.time_zone

动态分区时区设置,默认值为当前连接的时区。配置后将按照对应时区时间点进行动态分区管理。

您可以使用如下SQL查看可选的时区和offset等。返回结果中的name列即为timezone值,例如Asia/Shanghai。

SELECT * FROM pg_timezone_names;

auto_partitioning.num_precreate

预创建分区的数量,取值说明如下:

  • 0:不进行预创建。

  • [1, 512]:以当前时间点为基准创建分区,建议该值需要大于等于2,默认值为4。

说明

以当前时间为2022-01-10为例,time_unit = DAY,num_precreate = 3 参数配置即表示将创建2022-01-10、2022-01-11、2022-01-12三个分区。

重要

预创建分区行为会影响MAX_PT函数的行为,请配置前检查是否依赖MAX_PT函数。

auto_partitioning.num_retention

保留历史分区数量,取值说明如下:

  • 0:不保留历史分区。

  • -1(默认值):不清理历史分区。

  • 正数:保留N个历史分区,最大值为512。

可通过set hg_experimental_auto_part_max_maintained_partitions=<value>;调整保留分区的数量,最大值为8760。

说明

以当前时间为2022-01-10为例,<time_unit = DAY,num_retention = 3> 参数配置即表示将保留 2022-01-09、2022-01-08 、2022-01-07三个分区,早于2022-01-07的历史分区将被删除。

auto_partitioning.num_hot

保留热分区数量,取值说明如下:

  • 0:不保留热分区。

  • -1(默认值):不清理热分区。

  • 正数:保留N个热分区,最大值为512。

auto_partitioning.schd_start_time

自定义分区调度时间,当auto_partitioning.time_unit取值为HOUR时,分区调度时间默认为每个整点,若取其他值时,默认为当天的00:00:01。

表名生成规则

动态分区表时间单位auto_partitioning.time_unit取值为HOUR、DAY、MONTH、QUARTER、YEAR,动态分区将使用分区父表名加上时间后缀作为新创建分区的表名。格式如:{parent_table}_{time_suffix}, 其中时间后缀将依据自动分区的调度时间和时间单位对应的格式模板生成。具体的对应关系如下。

时间单位

时间后缀格式

示例

执行时间

HOUR

YYYYMMDDHH24

2022030117。

每个整点的开始,例如2022年3月1日 01:00:01执行任务。

DAY

YYYYMMDD

20220301。

每天00:00:01开始,例如2022年3月1日 00:00:01。

MONTH

YYYYMM

202203。

每个月的第一天00:00:01开始,例如2022年3月1日的00:00:01、2022年4月1日的00:00:01。

QUARTER

YYYYQ

20221、20222、20223、20224分别表示2022年的四个季度。

每个季度的第一天00:00:01开始,例如2022年1月1日 00:00:01。

YEAR

YYYY

2022、2023分别表示2022年、2023年的分区。

每年的第一天00:00:01开始,例如2022年1月1日 00:00:01。

使用示例

以天(DAY)为时间单位,预先创建未来3天的分区,保留近2天的历史分区,并将时区设置为Asia/Shanghai的代码示例如下。

V2.1版本起支持的语法示例

  1. 创建分区表tbl1

    -- 2.1版本创建分区表,并配置动态分区管理:
    
    CREATE TABLE tbl1 (
        c1 text NOT NULL,
        c2 text 
    )
    PARTITION BY LIST (c2)
    WITH (
       auto_partitioning_enable = 'true',
       auto_partitioning_time_unit = 'DAY',
       auto_partitioning_time_zone = 'Asia/Shanghai',
       auto_partitioning_num_precreate = '3',
       auto_partitioning_num_retention = '2'
    );
    
  2. 待子分区生成后插入数据。

    INSERT INTO tbl1 (c1, c2) VALUES ('Data 1', '20231212');
    INSERT INTO tbl1 (c1, c2) VALUES ('Data 2', '20231213');
    INSERT INTO tbl1 (c1, c2) VALUES ('Data 3', '20231214');
  3. 查询数据。

    SELECT * FROM tbl1 WHERE c2='20231212';

    返回结果如下:

    c1	     c2
    Data 1   20231212

所有版本支持的语法

  1. 创建分区表tbl1

    -- 创建分区表,并配置动态分区管理:
    BEGIN;
    CREATE TABLE tbl1 (
        c1 text NOT NULL,
        c2 text 
    )
    PARTITION BY LIST (c2);
    CALL set_table_property ('tbl1', 'auto_partitioning.enable', 'true');
    CALL set_table_property ('tbl1', 'auto_partitioning.time_unit', 'DAY');
    CALL set_table_property ('tbl1', 'auto_partitioning.time_zone', 'Asia/Shanghai');
    CALL set_table_property ('tbl1', 'auto_partitioning.num_precreate', '3');
    CALL set_table_property ('tbl1', 'auto_partitioning.num_retention', '2');
    COMMIT;
  2. 待子分区生成后插入数据。

    INSERT INTO tbl1 (c1, c2) VALUES ('Data 1', '20231212');
    INSERT INTO tbl1 (c1, c2) VALUES ('Data 2', '20231213');
    INSERT INTO tbl1 (c1, c2) VALUES ('Data 3', '20231214');
  3. 查询数据。

    SELECT * FROM tbl1 WHERE c2='20231212';

    返回结果如下:

    c1	     c2
    Data 1   20231212

分区增减的逻辑如下:

时间

事件

结果

2023-12-12 09:00:00

执行如上SQL,创建分区表。

  • 创建分区父表:tbl1

  • 创建分区子表:tbl1_20231212、tbl1_20231213、tbl1_20231214

2023-12-13 00:00:00

系统自动创建分区子表。

  • 创建分区子表:tbl1_20231215

2023-12-14 00:00:00

系统自动创建分区子表。

  • 系统创建分区子表:tbl1_20231216

2023-12-15 00:00:00

系统自动创建分区子表,并清理分区子表。

  • 创建分区子表:tbl1_20231217

  • 清理分区子表:tbl1_20231212

2023-12-16 00:00:00

系统自动创建分区子表,并清理分区子表。

  • 创建分区子表:tbl1_20231218

  • 清理分区子表:tbl1_20231213

常见场景

保留指定分区子表

默认情况下,系统会按照已配置的动态分区规则,自动创建和删除分区子表,不在保留范围内的分区子表将被自动删除。但在某些特殊场景中(例如在电商场景中,需要保留历年双11数据进行同环比分析),可能需要保留重要分区的数据,您可以通过给表增加keep_alive属性的方式,保留指定分区子表。使用语法介绍如下。

  • V2.1版本起支持的语法:

    -- 增加保留分区
    ALTER TABLE [<schema_name>.]<table_name> SET (keep_alive = 'true');
    
    -- 删除保留分区:删除保留属性后,动态分区管理会立即触发过期数据清理
    ALTER TABLE [<schema_name>.]<table_name> SET (keep_alive = 'false');
    
  • 所有版本支持的语法:

    -- 增加保留分区
    call set_table_property('[<schema_name>.]<table_name>', 'keep_alive', 'true');
    
    -- 删除保留分区:删除保留属性后,动态分区管理会立即触发过期数据清理
    call set_table_property('[<schema_name>.]<table_name>', 'keep_alive', 'false');

动态管理分区表的存储介质

在处理分区表时,采用冷热分层存储能够有效地平衡成本和性能。例如,可以动态保留最近N个历史分区在热存储以满足频繁的查询需求,而之后M个分区则可以存储在冷层以节约成本。在删除超过N和M分区数据的同时,结合动态管理分区的功能,可以实现此应用场景。

创建动态分区表

示例:设置每天一个分区,动态保留最近7个历史分区在热存储介质,超过7天之后的23个分区在冷存储介质,同时删除超过该范围的分区创建,代码示例如下。

BEGIN;
CREATE TABLE tbl2(	
  c1 text not null, 
  c2 text
)
PARTITION BY LIST(c2);
CALL set_table_property('tbl2', 'auto_partitioning.enable', 'true');
CALL set_table_property('tbl2', 'auto_partitioning.time_unit', 'DAY');
CALL set_table_property('tbl2', 'auto_partitioning.num_precreate', '3');
CALL set_table_property('tbl2', 'auto_partitioning.num_hot', '7');
CALL set_table_property('tbl2', 'auto_partitioning.num_retention', '30');
COMMIT;

效果如下图所示:

效果

修改存储策略

您可通过修改auto_partitioning.num_hot参数值,修改热存储介质的分区策略。需要注意的是,如果修改该策略,已经置为冷存的分区子表,不会自动变为热存。若现在是2022年7月1日,创建如下分区表。

BEGIN;
CREATE TABLE tbl_p(
  c1 text not null,
  c2 text
)
PARTITION BY LIST(c2);
CALL set_table_property('tbl_p', 'auto_partitioning.enable', 'true');
CALL set_table_property('tbl_p', 'auto_partitioning.time_unit', 'DAY');
CALL set_table_property('tbl_p', 'auto_partitioning.num_precreate', '3');
CALL set_table_property('tbl_p', 'auto_partitioning.num_hot', '3');
CALL set_table_property('tbl_p', 'auto_partitioning.num_retention', '10');
COMMIT;

此时的数据分布情况有如下两种场景:

  • 场景一:扩大使用热存储截止的分区策略

    如果需要将动态管理策略的热分区策略改为4个,则使用如下代码:

    CALL set_table_property('tbl_p', 'auto_partitioning.num_hot', '4');

    由于已经置为冷存的分区子表,不会自动的变为热存,则更改后的效果如下图所示:示例

  • 场景二:减小使用热存储截止的分区策略

    如果需要将动态管理策略的热分区策略改为2个,则使用如下代码:

    CALL set_table_property('tbl_p', 'auto_partitioning.num_hot', '2');

    由于已经置为冷存的分区子表,不会自动的变为热存,但是需要从热存变为冷存的数据会被迁移到冷存,则更改后的效果如下图所示:示例

将冷存分区表改为动态分区表

例如您需要将一张冷存属性的分区表,改为动态分区表且近7天分区设置为热存,可使用如下方法。

  1. 数据准备。

    -- 建表时指定存储策略为冷存储介质
    BEGIN;
    CREATE TABLE tbl2(	
      c1 text not null, 
      c2 text
    )
    PARTITION BY LIST(c2);
    CALL set_table_property('tbl2', 'storage_mode', 'cold');
    create table tbl2_20230808 partition of tbl2 for values in('20230808');
    create table tbl2_20230809 partition of tbl2 for values in('20230809');
    create table tbl2_20230810 partition of tbl2 for values in('20230810');
    create table tbl2_20230817 partition of tbl2 for values in('20230817');
    COMMIT;
  2. 修改动态分区表且将近7天分区设置为热存储。

    begin;
    CALL set_table_property('tbl2', 'storage_mode', 'hot'); --设置父表为hot
    CALL set_table_property('tbl2_20230810', 'storage_mode', 'cold'); --设置不需要转热的分区为cold
    CALL set_table_property('tbl2_20230809', 'storage_mode', 'cold');
    CALL set_table_property('tbl2_20230808', 'storage_mode', 'cold');
    CALL set_table_property('tbl2', 'auto_partitioning.enable', 'true');
    CALL set_table_property('tbl2', 'auto_partitioning.time_unit', 'DAY');
    CALL set_table_property('tbl2', 'auto_partitioning.num_precreate', '3');
    CALL set_table_property('tbl2', 'auto_partitioning.num_hot', '7');
    CALL set_table_property('tbl2', 'auto_partitioning.num_retention', '10');
    commit;

查看配置动态分区配置和调度情况

您可以通过如下SQL,查询当前数据库中配置了动态分区表信息和动态分区配置信息。

SELECT
    nsp_name AS schema_name,
    tbl_name AS table_name,
    ENABLE,
    time_unit,
    time_zone,
    num_precreate,
    num_retention,
    b.usename AS create_user,
    cret_time,
    schd_start_time,
    options
FROM
    hologres.hg_partitioning_config AS a
    LEFT JOIN pg_user AS b ON a.cret_user = b.usesysid;

以上字段名称介绍如下。

字段名称

说明

schema_name

schema名称。

table_name

表名称。

ENABLE

是否启用动态分区管理。

time_unit

动态分区的时间单位。

time_zone

动态分区时区设置。

num_precreate

预创建分区数量。

num_retention

保留历史分区数量。

create_user

创建用户。

cret_time

创建时间。

schd_start_time

最近一次计划调度时间。

查询结果如下。

image

查看创建和清除分区子表日志

Query Log中不记录创建和清除分区子表的日志,您可以使用如下SQL查询创建和清除分区子表日志。

SELECT                           
    relname,
    relowner,
    schdtime,
    trigtime,
    status,
    message,
    precreate,
    discard
FROM
    hologres.hg_partitioning_log 

以上字段名称介绍如下。

字段名称

说明

relname

schema.table

relowner

分区表的Owner。

schdtime

计划调度时间。

trigtime

实际触发时间。

status

状态。

message

备注。

precreate

创建的分区子表名。

discard

清理的分区子表名。

查询结果如下。

image

常见问题

对于存量分区表如何开启动态分区?

对于存量分区表您可以使用如下SQL开启动态分区。

-- Hologres V2.1版本SQL示例
ALTER TABLE auto_part_old SET (
   auto_partitioning_enable = 'true',
   auto_partitioning_time_unit = 'HOUR',
   auto_partitioning_time_zone = 'PRC',
   auto_partitioning_num_precreate = '4',
   auto_partitioning_num_retention = '-1',
   auto_partitioning_num_hot = '-1'
);

-- Hologres所有版本SQL示例
BEGIN;
CALL set_table_property('auto_part_old', 'auto_partitioning.enable', 'true');
CALL set_table_property('auto_part_old', 'auto_partitioning.time_unit', 'HOUR');
CALL set_table_property('auto_part_old', 'auto_partitioning.time_zone', 'PRC');
CALL set_table_property('auto_part_old', 'auto_partitioning.num_precreate', '4');
CALL set_table_property('auto_part_old', 'auto_partitioning.num_retention', '-1');
CALL set_table_property('auto_part_old', 'auto_partitioning.num_hot', '-1');
COMMIT;
重要

auto_partitioning.time_unitauto_partitioning.time_zone为动态分区功能的核心配置,Hologres升级后仅允许设置一次,设置后不能再更改。

存量分区表开启动态分区后,历史存在的分区子表是否会收到自动清理逻辑的影响?

系统根据分区子表的名称进行分区子表清理,若分区子表的名称满足{parent_table}_{time_suffix}命名规则,将会被清理,如果不满足则不会被清理。

创建动态分区指定了num_precreate为3,执行完SQL后父表创建成功,但并没有创建三个分区子表?

对于首次创建动态分区的任务,系统默认每10分钟检查一次,因此分区子表会在10分钟内被创建,请稍后查看。