tencent cloud

TDSQL Boundless

创建分区表

下载
聚焦模式
字号
最后更新时间: 2026-05-26 17:37:40

概述

分区表 (Partition Table) 是 TDSQL Boundless 处理海量数据和实现水平扩展的核心手段。与单表不同,分区表通过分区键 (Partition Key) 将数据打散分布到集群中的多个存储节点上,使数据库能够利用集群整体的计算能力和存储空间,突破单机的性能瓶颈。

什么时候应该使用分区表?

如果您的业务符合以下任一特征,建议选择分区表:
1. 数据量大或高并发写入:需要支持极高的写入吞吐 (TPS),单机无法承载。
2. 数据无限增长:业务处于快速发展期,无法预估未来的数据上限。

选择分区策略

TDSQL Boundless 支持如下几种分区策略,选择正确的策略是建表最关键的一步。
1. HASH 分区
简介:对分区键值进行取模运算,将数据随机且均匀地打散。
适用场景:最推荐的默认选择。适用于分区键为整数 (INT / BIGINT) 的场景,如用户 ID、纯数字订单号。
优势:负载均衡效果好,写入性能高。
2. KEY 分区
简介:类似 HASH,但支持除 BLOB / TEXT 外的多种数据类型,系统使用内部哈希函数处理数据。
适用场景:分区键为字符串 (VARCHAR / CHAR) 的场景,如 UUID、身份证号、业务流水号。
优势:解决了字符串无法直接进行 HASH 取模的问题,无需业务层转换。
3. RANGE 分区
简介:根据键值的连续区间(如时间段、ID 段)划分数据。
适用场景:时间序列数据,如日志、流水、监控等。
优势:范围查询快,可以通过 DROP PARTITION 秒级删除过期的历史数据。
4. LIST 分区
简介:根据枚举值(离散列表)划分数据。
适用场景:具有明确类别属性的数据,如地域(省份、城市)、租户 ID。
优势:数据归类清晰,便于按类别隔离管理。
风险:数据倾斜。如果某个类别(如 “广东省”)的数据量远超其他类别,该节点会成为瓶颈。
5. 二级分区
简介:在已有的一级分区基础上,对每个分区再次进行细分。与 MySQL 8.0 规范保持一致,一级分区仅支持 RANGE 或 LIST,二级分区仅支持 HASH 或 KEY。
适用场景:数据量极大,且具有多维度的查询和管理需求。例如,先按时间(RANGE)进行一级分区以便于历史数据清理,再按用户 ID(HASH/KEY)进行二级分区以打散热点数据,提升并发写入性能。
优势:结合了范围/列表分区的管理便利性和哈希/键分区的负载均衡能力。
风险:总分区数为“一级 × 二级”,过多分区会急剧增加系统的元数据管理开销,消耗大量内存和文件句柄,并导致 DDL 操作变慢。建议单表总分区数控制在8192以内。

语法与示例

场景 A:标准电商订单(使用 HASH)

分区键为纯数字 ID。
CREATE TABLE `mall`.`orders` (
`order_id` bigint NOT NULL,
`user_id` bigint NOT NULL,
`amount` decimal(10,2),
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
-- 主键必须包含分区键
PRIMARY KEY (`order_id`)
)
PARTITION BY HASH(`order_id`)
PARTITIONS 64;

场景 B:用户中心(使用 KEY)

分区键为 UUID 字符串,使用 KEY 分区自动处理哈希。
CREATE TABLE `user_center`.`user_profiles` (
`user_uuid` varchar(36) NOT NULL,
`nick_name` varchar(50),
`register_time` datetime,
PRIMARY KEY (`user_uuid`)
)
PARTITION BY KEY(`user_uuid`)
PARTITIONS 64;

场景 C:操作日志(按月 RANGE 分区)

适用于操作日志、流水、监控等时间序列数据,且需要定期按时间清理的场景。
TDSQL Boundless 当前支持的分区类型为 RANGERANGE COLUMNSLISTLIST COLUMNSHASHKEY
注意:
针对时间序列场景,需注意:不支持 “自动预创建未来分区 ”。建表时需要预定义未来一段时间的分区,并通过运维手段(外部调度任务)周期性预创建新分区。

建表示例:预定义 RANGE 分区

CREATE TABLE `sys`.`audit_logs` (
`log_id` bigint NOT NULL,
`content` text,
`log_time` datetime NOT NULL,
PRIMARY KEY (`log_id`, `log_time`)
)
PARTITION BY RANGE COLUMNS(`log_time`) (
PARTITION p202601 VALUES LESS THAN ('2026-02-01'),
PARTITION p202602 VALUES LESS THAN ('2026-03-01'),
PARTITION p202603 VALUES LESS THAN ('2026-04-01')
);
注意:
不建议使用 PARTITION p_future VALUES LESS THAN (MAXVALUE) 作为兜底分区
MAXVALUE 是静态兜底分区,不会随时间自动按月分裂。一旦写入超出最后一个分区上界的数据,所有新数据会持续落入 p_future,导致:
p_future 无限膨胀,失去按月清理的能力;
后续若想 ADD PARTITION p202304,会因 MAXVALUE 已占据末尾而直接报错,必须先 REORGANIZE PARTITION p_future,操作复杂且代价高。
推荐做法:建表时预定义未来3 - 6个月的分区,并配合定时任务每月底提前 ADD PARTITION 预创建下一个月分区。

RANGE 分区常用维护操作

操作场景
SQL 示例
说明
删除过期分区
ALTER TABLE sys.audit_logs DROP PARTITION p202601;
秒级清理过期数据,性能远优于 DELETE
清空分区数据
ALTER TABLE sys.audit_logs TRUNCATE PARTITION p202601;
保留分区结构,仅清空数据
预创建下月分区
ALTER TABLE sys.audit_logs ADD PARTITION (PARTITION p202604 VALUES LESS THAN ('2026-05-01'));
仅可在末尾新增,值必须严格递增
拆分 MAXVALUE 分区
ALTER TABLE sys.audit_logs REORGANIZE PARTITION p_future INTO (PARTITION p202603 VALUES LESS THAN ('2026-04-01'), PARTITION p_future VALUES LESS THAN (MAXVALUE));
误用 MAXVALUE 后的补救手段
查看分区列表
SELECT PARTITION_NAME, PARTITION_DESCRIPTION, TABLE_ROWS FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA='sys' AND TABLE_NAME='audit_logs';
查询当前分区状态与数据量

推荐方案:外部周期性预创建分区

环节
推荐方案
说明
未来分区预创建
通过外部调度任务执行 ALTER TABLE ... ADD PARTITION
系统不会自动按时间扩展分区,必须由外部周期性触发

场景 D:按地域分布(使用 LIST)

业务明确按城市划分,且不同城市数据隔离。
CREATE TABLE `crm`.`customers` (
`cust_id` bigint NOT NULL,
`city_id` int NOT NULL,
`name` varchar(50),
PRIMARY KEY (`cust_id`, `city_id`)
)
PARTITION BY LIST(`city_id`) (
PARTITION p_bj VALUES IN (10),
PARTITION p_sh VALUES IN (20),
PARTITION p_others VALUES IN (30)
);

场景 E:海量历史流水表(使用 RANGE + HASH 二级分区)

适用于既需要按时间周期清理历史数据,又面临极高并发写入、需要将单月数据进一步打散的场景。
一级分区按月 RANGE 分区,二级分区按用户 ID HASH 分区。
CREATE TABLE `sys`.`massive_logs` (
log_id bigint NOT NULL,
user_id bigint NOT NULL,
content text,
log_time datetime NOT NULL,
PRIMARY KEY (log_id, log_time, user_id))
PARTITION BY RANGE COLUMNS(log_time)
SUBPARTITION BY HASH(user_id)
SUBPARTITIONS 4
(PARTITION p202601 VALUES LESS THAN ('2026-02-01'),
PARTITION p202602 VALUES LESS THAN ('2026-03-01'),
PARTITION p202603 VALUES LESS THAN ('2026-04-01')
);

关键约束

分区表有一个必须遵守的硬性约束,违反该约束将导致建表失败:
主键和唯一索引必须包含分区键。
错误示例:
-- 错误:分区键 user_id 没有包含在主键中
CREATE TABLE `error_table` (
`id` bigint NOT NULL PRIMARY KEY,
`user_id` bigint NOT NULL
) PARTITION BY HASH(`user_id`);
正确示例:
-- 正确:将 user_id 加入联合主键
CREATE TABLE `correct_table` (
`id` bigint NOT NULL,
`user_id` bigint NOT NULL,
PRIMARY KEY (`id`, `user_id`)
) PARTITION BY HASH(`user_id`);

实践建议

1. 分区数量
策略:预分片不要仅考虑当前的物理节点数,需同时考虑未来集群规模和预期数据总量。
推荐值:建议设置为 “预期未来最大节点数 × 2”,以确保数据充分分散。
2. 避免修改分区键
尽量避免 UPDATE 语句修改分区键的值,这可能会导致数据行在物理节点间迁移(DELETE + INSERT),代价较高。
3. 查询优化
带上分区键:查询时尽量在 WHERE 子句中带上分区键(如 WHERE user_id = ?),TDSQL Boundless 可以直接路由到特定节点,性能极高。
避免全表扫描:不带分区键的查询会触发广播扫描 (Scatter-Gather),查询所有节点并汇总,消耗大量资源。

常见问题

HASH 和 KEY 分区有什么区别?

HASH 主要处理整数,算法简单直接;KEY 主要处理字符串(也支持整数),内部使用复杂的哈希函数。如果是字符串 ID,请直接使用 KEY 分区。

可以使用多个列做分区键吗?

可以,例如 PARTITION BY HASH(col1 + col2) KEY(col1, col2)。但这会增加复杂性,通常建议使用单一的高基数列作为分区键。

建表后可以修改分区键或分区类型吗?

极不推荐。虽然语法上支持,但这本质上是一次全量数据的 “重新洗牌”,会消耗巨大的系统资源(IO 与 CPU),并可能导致长时间的业务阻塞。

RANGE 分区设了 MAXVALUE 兜底,下个月会自动建分区吗?

不会。MAXVALUE 是静态兜底分区,新数据只会落入该分区,不会自动按月分裂。TDSQL Boundless 系统暂不支持自动预创建未来分区,需要通过外部调度任务定期执行 ALTER TABLE ... ADD PARTITION 来预创建下一个时间段的分区。

分区表能修改分区策略吗?

可以,通过 ALTER TABLE ... REMOVE PARTITIONING 移除分区后重新定义,或者直接 ALTER TABLE ... PARTITION BY RANGE COLUMNS(...) (...) 重建分区策略。注意:重建分区会涉及数据重组,大表请评估代价并选择业务低峰期执行。

写入了超过最后一个分区上界的数据会发生什么?

如果建表时未定义 MAXVALUE 兜底分区,写入会报错 ER_NO_PARTITION_FOR_GIVEN_VALUE,提示 “Table has no partition for value xxx”。这是预期行为,可以作为 “忘记预创建分区”的兜底告警信号,避免数据静默落入 MAXVALUE 分区造成后续清理困难。

相关操作

帮助和支持

本页内容是否解决了您的问题?

填写满意度调查问卷,共创更好文档体验。

文档反馈