概述
分区表 (Partition Table) 是 TDSQL Boundless 处理海量数据和实现水平扩展的核心手段。与单表不同,分区表通过分区键 (Partition Key) 将数据打散分布到集群中的多个存储节点上。这使得数据库能够利用集群整体的计算能力和存储空间,突破单机的性能瓶颈。
什么时候应该使用分区表?
如果您的业务符合以下任一特征,请务必选择分区表:
1. 数据量大或者高并发写入:需要支持极高的写入吞吐(TPS),单机无法承载。
2. 无限增长:业务处于快速发展期,无法预估未来的数据上限。
选择分区策略
TDSQL Boundless 支持四种主要的分区策略。选择正确的策略是建表最关键的一步。
1. HASH 分区
简介:对分区键值进行取模运算,将数据随机且均匀地打散。
适用场景:最推荐的默认选择。适用于分区键是 整数 (INT/BIGINT) 的场景,如用户 ID、纯数字订单号。
优势:负载均衡效果好,写入性能高。
2. KEY 分区
简介:类似于 HASH,但支持除 BLOB/TEXT 外的多种数据类型。系统使用内部哈希函数处理数据。
适用场景:分区键是字符串 (VARCHAR/CHAR) 的场景,如 UUID、身份证号、业务流水号(String)。
优势:解决了字符串无法直接进行 HASH 取模的问题,无需业务层转换。
3. RANGE 分区
简介:根据键值的连续区间(如时间段、ID 段)划分数据。
适用场景:时间序列数据(日志、流水、监控)。
优势:范围查询快,且可以通过 DROP PARTITION 秒删过期的历史数据。
4. LIST 分区
简介:根据枚举值(离散列表)划分数据。
适用场景:具有明确类别属性的数据,如地域(省份/城市)、租户 ID。
优势:数据归类清晰,便于按类别隔离管理。
风险:数据倾斜。如果某个类别(如“广东省”)的数据量远超其他类别,该节点会成为瓶颈。
语法与示例
场景 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)
按月存储日志,便于定期清理旧数据。
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 p202301 VALUES LESS THAN ('2023-02-01'),PARTITION p202302 VALUES LESS THAN ('2023-03-01'),PARTITION p_future VALUES LESS THAN (MAXVALUE));
场景 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));
关键约束 (Critical Constraints)
分区表有一个必须遵守的硬性约束,违反该约束将导致建表失败:
主键和唯一索引必须包含分区键。
错误示例:
-- 错误:分区键 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),查询所有节点并汇总,消耗大量资源。
常见问题 (FAQ)
Q: HASH 和 KEY 分区有什么区别?
A: HASH 主要处理整数,算法简单直接;KEY 主要处理字符串(也支持整数),内部使用复杂的哈希函数。如果是字符串 ID,请直接用 KEY 分区。
Q: 我可以用多个列做分区键吗?
A: 可以,例如
PARTITION BY HASH(col1 + col2) 或 KEY(col1, col2)。但这会增加复杂性,通常建议使用单一的高基数列作为分区键。Q: 建表后可以修改分区键或分区类型吗?
A: 极不推荐。 虽然语法上支持,但这本质上是一次全量数据的“重新洗牌”,会消耗巨大的系统资源(IO/CPU)并可能导致长时间的业务阻塞。