概述
INTERVAL RANGE 分区是 RANGE 分区(含 RANGE COLUMNS)的增强能力。通过在建表或变更表时声明一个固定步长(
INTERVAL),系统可以在 INSERT 写入超出现有分区范围的数据时,自动创建所需的新分区,无需人工或外部脚本定期执行 ALTER TABLE ... ADD PARTITION。该能力主要解决时间序列业务的运维痛点:使用普通 RANGE 分区时,如果忘记提前创建下一个时间段(或 ID 区间)的分区,INSERT 会直接报错
ER_NO_PARTITION_FOR_GIVEN_VALUE,导致业务写入中断。声明 INTERVAL 后,只要写入的值合法,正常情况下不会因为分区不存在而失败。说明:
INTERVAL RANGE 分区是对标准 RANGE 分区语法的扩展,仅需在
PARTITION BY RANGE(...) 或 PARTITION BY RANGE COLUMNS(...) 后追加 INTERVAL(...) 子句即可,无需改变现有分区表的使用方式。前提条件
该功能自 V21.6.4.0 及以上版本开始支持,V21.6.4.0以下版本不支持声明 INTERVAL 分区。
系统变量
interval_partitioning_enabled 需为 ON(默认开启)。该变量关闭后,CREATE TABLE / ALTER TABLE 中的 INTERVAL 子句会直接报错,已有 INTERVAL 表的 INSERT 自动建分区功能也会被跳过(仅告警,不阻断写入,但越界数据会因分区不存在而报错)。仅支持顶层
PARTITION BY RANGE(expr) 或 PARTITION BY RANGE COLUMNS(column),且 RANGE COLUMNS 仅支持单列。LIST、HASH、KEY 分区不支持声明 INTERVAL。若为二级分区表,子分区必须是 HASH/KEY 类型。建表时必须至少预定义1个初始分区。
语法
CREATE TABLE 时声明:
CREATE TABLE table_name (column_definitions)PARTITION BY { RANGE(expr) | RANGE COLUMNS(column) }INTERVAL({ interval_type, N | N })(partition_definition [, partition_definition] ...);
对已有 RANGE 表追加或调整 INTERVAL(纯元数据操作,不涉及数据搬迁):
-- 追加或修改 INTERVAL 步长ALTER TABLE table_name SET INTERVAL({ interval_type, N | N });-- 清除 INTERVAL 属性,降级为普通 RANGE 表ALTER TABLE table_name SET INTERVAL();
参数说明
参数 | 说明 |
interval_type | 时间间隔类型,仅支持8种关键字: YEAR、QUARTER、MONTH、WEEK、DAY、HOUR、MINUTE、SECOND。仅用于 RANGE COLUMNS 且分区列为日期时间类型时。 |
N | 间隔数值,必须为正整数常量,取值需 > 0(不支持子查询、列引用、变量)。时间类型为 SECOND 时,N 不能小于60。省略 interval_type 时按整数步长处理,仅适用于分区表达式为整数场景。 |
INTERVAL() | 空括号,仅用于 ALTER TABLE SET INTERVAL(),表示清除已声明的 INTERVAL 属性。 |
分区列类型与 INTERVAL 类型的对应关系
分区列类型 | 支持的 INTERVAL 写法 |
INT/BIGINT/SMALLINT/TINYINT/MEDIUMINT(含 UNSIGNED)、RANGE(expr) 表达式 | 仅 INTERVAL(N)(整数步长) |
DATE | INTERVAL(YEAR, N)、QUARTER、MONTH、WEEK、DAY |
TIME | INTERVAL(HOUR, N)、MINUTE、SECOND |
DATETIME | 以上时间类型均支持 |
TIMESTAMP、CHAR/VARCHAR/TEXT/BLOB、ENUM/SET、DECIMAL/FLOAT/DOUBLE | 不支持声明 INTERVAL。 TIMESTAMP 类型可改用 PARTITION BY RANGE(UNIX_TIMESTAMP(ts)) INTERVAL(N)(此时 N 单位为秒,同样要求 ≥ 60) |
注意:
生成列(
GENERATED ALWAYS AS)、表达式默认值列(DEFAULT (expr))、AUTO_INCREMENT 列不能作为 INTERVAL 分区键。分区键为函数表达式(如
RANGE(MONTH(dt)))时,声明的 N 不能超出该表达式的合理取值范围(例如 MONTH(dt) 的值域为1 ~ 12)。系统变量
以下系统变量均为
GLOBAL 作用域,支持动态修改:变量名 | 默认值 | 取值范围 | 说明 |
interval_partitioning_enabled | ON | ON/OFF | INTERVAL 分区功能总开关。关闭后拒绝新建 INTERVAL 声明,已有 INTERVAL 表的自动建分区能力也会被跳过。 |
interval_partitioning_support_auto_add_in_trx | ON | ON/OFF | 控制显式事务( BEGIN/START TRANSACTION)中的 INSERT 是否允许触发自动建分区。关闭后,显式事务中的越界写入直接报 ER_NO_PARTITION_FOR_GIVEN_VALUE,需要在自动提交模式下写入。 |
interval_partitioning_support_duplicate_key_update | OFF | ON/OFF | 控制 INSERT ... ON DUPLICATE KEY UPDATE 语句是否允许触发自动建分区。 |
interval_partitioning_max_auto_add_count | 64 | [1, 1024] | 单次 INSERT 最多允许自动创建的分区数量,超过则整条 INSERT 失败(不会产生部分写入)。 |
interval_partitioning_max_auto_add_retries | 5 | [1, 60] | 自动建分区过程中遇到锁等待超时等可重试的瞬态错误时,内部重试的次数上限。 |
使用限制
场景 | 行为说明 |
INSERT INTO t VALUES (...)(单行/多行) | 越界值触发自动建分区 |
INSERT ... SELECT | 不触发(写入值需执行期才能确定) |
VALUES 中含标量子查询、存储过程参数、预处理占位符 | 不触发(非常量表达式无法提前计算应落入的分区) |
INSERT ... ON DUPLICATE KEY UPDATE | 由 interval_partitioning_support_duplicate_key_update 控制,默认关闭 |
INSERT IGNORE、REPLACE | 正常触发自动建分区 |
LOCK TABLES 模式下的 INSERT | 跳过自动建分区(仅告警,不阻断,越界数据仍会报错) |
触发器、存储函数内部的 INSERT | 跳过自动建分区(仅告警) |
显式事务中的 INSERT | 由 interval_partitioning_support_auto_add_in_trx 控制,默认允许 |
写入值落在已有分区范围左侧(更小的值) | 不会自动建分区,仅向后(更大方向)扩展 |
UPDATE、DELETE、SELECT | 均不触发自动建分区 |
单次 INSERT 触发的自动建分区数量不超过
interval_partitioning_max_auto_add_count(默认64),超出则整条语句失败,不会残留部分创建的分区。自动分区命名规则
自动创建的分区统一以
_p 为前缀,后接边界值:分区列类型 | 命名格式 | 示例 |
整数( INT/BIGINT 等) | _p<数值> | _p1000 |
DATE | _p<YYYYMMDD> | _p20260201 |
DATETIME | _p<YYYYMMDDhhmmss> | _p20260201000000 |
TIME | _p<hhmmss> | _p120000 |
注意:
手动创建分区时,如果分区名以
_p 开头,该名称必须与系统按当前边界值自动生成的名称完全一致,否则会报错拒绝建表或变更(错误信息为分区命名冲突)。建议手动分区统一不使用 _p 前缀,避免与自动命名冲突。示例
示例1:整数步长——订单表按 ID 自动分区
分区键为整型,按1000为步长自动扩展。注意
AUTO_INCREMENT 列不能作为 INTERVAL 分区键,因为自增值在存储引擎内部分配,计算阶段不可知。CREATE TABLE orders (order_id BIGINT NOT NULL,user_id BIGINT NOT NULL,amount DECIMAL(10,2),PRIMARY KEY (order_id))PARTITION BY RANGE(order_id) INTERVAL(1000) (PARTITION p0 VALUES LESS THAN (1000));-- 写入超出现有分区范围的数据,触发自动建分区INSERT INTO orders (order_id, user_id, amount) VALUES (2500, 1001, 99.90);SHOW CREATE TABLE orders;
SHOW CREATE TABLE 输出中会以版本化注释 /*B!210604 INTERVAL(1000) */ 携带 INTERVAL 声明,并可见系统自动创建的 _p2000、_p3000 等分区:CREATE TABLE `orders` (`order_id` bigint NOT NULL,`user_id` bigint NOT NULL,`amount` decimal(10,2) DEFAULT NULL,PRIMARY KEY (`order_id`)) ENGINE=ROCKSDB DEFAULT CHARSET=utf8mb4/*!50100 PARTITION BY RANGE (`order_id`) */ /*B!210604 INTERVAL(1000) */ /*!50100(PARTITION p0 VALUES LESS THAN (1000) ENGINE = ROCKSDB,PARTITION _p2000 VALUES LESS THAN (2000) ENGINE = ROCKSDB,PARTITION _p3000 VALUES LESS THAN (3000) ENGINE = ROCKSDB) */
示例2:按月自动分区——日志表按时间自动扩展
分区键为日期列,按月自动创建新分区,彻底免去每月手动
ADD PARTITION 的运维操作。CREATE TABLE audit_logs (log_id BIGINT NOT NULL,content TEXT,log_time DATE NOT NULL,PRIMARY KEY (log_id, log_time))PARTITION BY RANGE COLUMNS(log_time) INTERVAL(MONTH, 1) (PARTITION p0 VALUES LESS THAN ('2026-02-01'));-- 写入 4 月的数据,系统自动补齐 2/3/4 月分区INSERT INTO audit_logs (log_id, log_time) VALUES (1, '2026-04-15');SELECT PARTITION_NAME, PARTITION_DESCRIPTIONFROM INFORMATION_SCHEMA.PARTITIONSWHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='audit_logs'ORDER BY PARTITION_ORDINAL_POSITION;
INFORMATION_SCHEMA.PARTITIONS 中可以看到系统自动创建了 _p20260301、_p20260401、_p20260501 三个分区,覆盖到写入值所在的月份。示例3:为已有 RANGE 表追加 INTERVAL 属性
对已经存在、未声明 INTERVAL 的 RANGE 表,可通过
ALTER TABLE ... SET INTERVAL(...) 追加该属性,该操作仅修改元数据,不涉及数据搬迁:CREATE TABLE t_range (id BIGINT NOT NULL PRIMARY KEY) ENGINE=ROCKSDBPARTITION BY RANGE(id) (PARTITION p0 VALUES LESS THAN (1000));-- 追加整数步长 100ALTER TABLE t_range SET INTERVAL(100);-- 后续 INSERT 越界值将自动建分区INSERT INTO t_range VALUES (1050);
示例4:清除 INTERVAL 属性,降级为普通 RANGE 表
ALTER TABLE t_range SET INTERVAL();SHOW CREATE TABLE t_range;-- 清除后,越界写入将不再自动建分区,直接报错INSERT INTO t_range VALUES (2000);-- ERROR: Table has no partition for value 2000
常见问题
INTERVAL 分区和普通 RANGE 分区可以相互切换吗?
可以。对普通 RANGE 表执行
ALTER TABLE ... SET INTERVAL(...) 即可追加该属性;对 INTERVAL 表执行 ALTER TABLE ... SET INTERVAL()(空括号)即可清除该属性、降级为普通 RANGE 表。两个方向均为纯元数据操作,不涉及数据搬迁。声明 INTERVAL 后,还需要用外部脚本定期 ADD PARTITION 吗?
不需要。只要写入的数据在有效取值范围内,系统会在 INSERT 时自动创建所需的分区。仍然可以手动执行
ALTER TABLE ... ADD PARTITION 提前创建分区,与自动建分区互不冲突。自动创建分区的过程会影响 INSERT 的事务性吗?
自动建分区通过独立事务执行 DDL,DDL 提交后新分区即持久化、不可回滚;如果后续 INSERT 主体因唯一键冲突等原因失败,已创建的分区不会被撤销,后续写入仍可正常使用这些分区。
一次 INSERT 需要跨越很多个分区(例如迁移历史数据)会怎样?
单次 INSERT 自动创建的分区数不能超过
interval_partitioning_max_auto_add_count(默认 64),超过时整条语句失败,不会插入任何数据。如需一次性回补大量历史区间,建议提前通过 ALTER TABLE ... ADD PARTITION 手动分批创建分区,或调大该系统变量后再执行。关闭 interval_partitioning_enabled 后,已有的 INTERVAL 表会怎样?
已有 INTERVAL 表的分区定义不受影响,
SHOW CREATE TABLE 仍会显示 INTERVAL 声明。但该变量关闭期间,INSERT 越界数据不会再自动建分区(仅产生告警),需要手动执行 ADD PARTITION 补齐,或重新打开该变量。