自动分区

更新时间:
复制为 MD 格式

自动分区功能在数据写入时,可根据分区列的实际数据自动创建分区,无需预先定义。它解决了因分区列数据分布零散或难以预测,而导致需要手动维护大量分区的难题。

概述

分区是数据库中一种重要的数据管理方式。通常,您需要在建表时手动定义所有分区,或使用动态分区功能按固定时间周期自动创建分区。

  • 手动分区:适用于分区数量固定且有限的场景。当分区数量庞大或分区范围无法预知时,手动创建和维护将变得极其繁琐。

  • 动态分区:适用于基于当前系统时间的实时数据场景(例如用户行为日志),可按天或按月自动创建新分区。但它不适用于分区列与当前时间无关的历史数据导入场景。

自动分区(AUTO PARTITION)旨在解决上述问题。它允许数据库在数据导入时,根据数据本身的值按需创建分区,无需预先定义。该功能在处理分区列包含大量离散值或数据范围不确定的历史数据时尤其高效。

例如,一个按年分区的交易历史表,若使用手动分区,其 DDL 可能如下所示,需要预先定义每年的分区:

-- 手动分区的示例
CREATE TABLE `DAILY_TRADE_VALUE_MANUAL`
(
    `TRADE_DATE`              datev2 NOT NULL COMMENT '交易日期',
    `TRADE_ID`                varchar(40) NOT NULL COMMENT '交易编号'
)
UNIQUE KEY(`TRADE_DATE`, `TRADE_ID`)
PARTITION BY RANGE(`TRADE_DATE`)
(
    PARTITION p_2000 VALUES [('2000-01-01'), ('2001-01-01')),
    PARTITION p_2001 VALUES [('2001-01-01'), ('2002-01-01')),
    PARTITION p_2002 VALUES [('2002-01-01'), ('2003-01-01')),
    -- ... 需要手动添加更多年份的分区 ...
    PARTITION p_2021 VALUES [('2021-01-01'), ('2022-01-01'))
)
DISTRIBUTED BY HASH(`TRADE_DATE`) BUCKETS 10
PROPERTIES ( "replication_num" = "1" );

如果采用自动分区,DDL 将大幅简化。您只需定义分区规则,系统便会在数据写入时(例如,当一条 `TRADE_DATE` 为 `2022-05-10` 的数据写入时)自动创建所需的分区(例如 `p20220101000000`)。

-- 自动分区的示例
CREATE TABLE `DAILY_TRADE_VALUE_AUTO`
(
    `TRADE_DATE`              datev2 NOT NULL COMMENT '交易日期',
    `TRADE_ID`                varchar(40) NOT NULL COMMENT '交易编号'
)
UNIQUE KEY(`TRADE_DATE`, `TRADE_ID`)
AUTO PARTITION BY RANGE (date_trunc(`TRADE_DATE`, 'year'))
(
)
DISTRIBUTED BY HASH(`TRADE_DATE`) BUCKETS 10
PROPERTIES ( "replication_num" = "1" );

使用方法

重要

自动分区功能仅支持4.0.0及以上版本实例。

CREATE-TABLE语句中,您可以通过 `AUTO PARTITION BY` 关键字定义自动分区规则,以替代原有的 `partitions_definition` 部分。自动分区支持 `RANGE` 和 `LIST` 两种类型。

AUTO RANGE PARTITION

适用于对日期或时间类型的列进行范围分区的场景。

语法

[AUTO] PARTITION BY RANGE(date_trunc(<partition_column>, '<interval>'))
()
  • `AUTO` 关键字在 `RANGE` 分区中可以省略。

  • <partition_column>:分区列,必须为 `DATE` 或 `DATETIME` 类型。

  • <interval>:时间粒度,支持 `year`、`month`、`day`、`hour`。

示例

CREATE TABLE `date_table` (
    `TIME_STAMP` datev2 NOT NULL
)
ENGINE=OLAP
DUPLICATE KEY(`TIME_STAMP`)
AUTO PARTITION BY RANGE (date_trunc(`TIME_STAMP`, 'month'))
()
DISTRIBUTED BY HASH(`TIME_STAMP`) BUCKETS 10
PROPERTIES ( "replication_allocation" = "tag.location.default: 1" );

AUTO LIST PARTITION

适用于基于枚举值进行分区的场景。系统会为分区列中出现的每一个唯一值(或值的组合)创建一个独立分区。

语法

AUTO PARTITION BY LIST(`partition_col1` [, `partition_col2`, ...])
()
  • 支持单列或多列分区。

示例

CREATE TABLE `city_table` (
    `user_id` INT,
    `city` VARCHAR(20) NOT NULL
)
ENGINE=OLAP
DUPLICATE KEY(`user_id`)
AUTO PARTITION BY LIST (`city`)
()
DISTRIBUTED BY HASH(`user_id`) BUCKETS 10
PROPERTIES ( "replication_allocation" = "tag.location.default: 1" );

规则与限制

AUTO RANGE PARTITION

  • 分区函数仅支持 `date_trunc`。

  • 分区列仅支持 `DATE` 和 `DATETIME` 数据类型。

  • 不支持将可为空(NULLABLE)的列作为分区列。

AUTO LIST PARTITION

  • 不支持在分区列上使用函数调用。

  • 支持的分区列数据类型包括:`BOOLEAN`, `TINYINT`, `SMALLINT`, `INT`, `BIGINT`, `LARGEINT`, `DATE`, `DATETIME`, `CHAR`, `VARCHAR`。

  • 自动生成的分区名长度上限为 50 个字符。由于分区名由各分区列的值拼接而成,请确保分区列值的组合长度在此限制内。

NULL 值分区

当会话变量 allow_partition_column_nullable 设置为 `true` 时,支持对可为空(NULLABLE)的列进行分区,具体规则如下:

  • AUTO LIST PARTITION:支持使用可为空的列作为分区列。当写入 `NULL` 值时,系统会自动创建一个专门用于存储 `NULL` 值的分区。

  • AUTO RANGE PARTITION:即使开启此变量,依然不支持使用可为空的列作为分区列。

通用规则

  • 为防止意外创建过多分区,单个自动分区表的最大分区数由 FE 配置项 max_auto_partition_num 控制,默认为 1024。您可以根据需要调整此配置。

  • 自动分区表在功能和使用上与普通分区表基本一致,仅分区创建方式由手动变为自动。

  • 在数据导入过程中,如果因任务失败或取消导致已创建的新分区中未写入任何数据,系统不会自动删除这些空分区。

  • 如果在导入数据并创建分区的同时,该表正在进行其他元数据操作(例如 Schema Change),则导入任务可能会失败。

高级功能

生命周期管理

自动分区表(仅限 `AUTO RANGE PARTITION`)通过专属属性实现分区生命周期管理,因此不推荐再与动态分区功能混合使用。

您可以在 `PROPERTIES` 中设置 partition.retention_count 属性来自动淘汰过期的历史分区。该属性定义了需要保留的历史分区数量,系统将删除超出此数量的最旧历史分区。

  • 历史分区:分区的上界(Range 的结束时间)小于或等于当前时间的分区。

  • 当前及未来分区:分区的上界大于当前时间的分区。这些分区不受 `partition.retention_count` 属性的影响。

示例

假设当前日期为 `2025-10-21`,下表设置保留 3 个历史分区。在写入 `2025-10-16` 到 `2025-10-23` 的数据后,系统会创建每日分区。

CREATE TABLE auto_recycle(
    k0 DATETIME NOT NULL
)
AUTO PARTITION BY RANGE (date_trunc(k0, 'day')) ()
DISTRIBUTED BY HASH(`k0`) BUCKETS 1
PROPERTIES(
    "partition.retention_count" = "3"
);

经过分区回收后,系统会保留如下分区:

  • `p20251018`、`p20251019`、`p20251020`:最新的 3 个历史分区被保留。

  • `p20251021`、`p20251022`、`p20251023`:当前及未来分区被保留。

  • `p20251016`、`p20251017`:更早的历史分区被删除。

与自动分桶联用

AUTO RANGE PARTITION 支持与自动分桶功能联用。此组合的使用前提是,数据按时间顺序增量导入,即每次导入仅涉及最新的分区。

注意:如果数据导入模式不符合上述假设(例如,同时向多个历史分区写入数据),自动分桶功能可能会导致分桶数设置不合理,进而严重影响查询性能,请谨慎使用。

分区管理

由于分区及其名称均为自动生成,您需要使用 auto_partition_name 函数和 partitions 表函数来查询和管理这些分区。

查询分区信息

以下示例演示了如何查询包含日期 `2008-02-03` 的分区信息:

SELECT *
FROM partitions("catalog"="internal", "database"="db_name", "table"="DAILY_TRADE_VALUE_AUTO")
WHERE PartitionName = auto_partition_name('range', 'year', '2008-02-03');

数据加载

  • 向自动分区表导入数据时,其内部轮询间隔与普通表不同,由 BE 配置项 olap_table_sink_send_interval_auto_partition_factor 控制。如果开启了前移(`enable_memtable_on_sink_node = true`),则此参数不生效。

  • 关于使用 `INSERT OVERWRITE` 语句向自动分区表写入数据的具体行为,请参考其功能文档