OceanBase分区基础知识

介绍

分析型业务通常需要对海量数据进行分析计算,这对数据库的查询能力,以及数据管理能力都有很高的要求。OceanBase通过分区技术,将一张表的数据按照分区键水平拆分成多个数据子集,有助于提升查询效率和数据管理能力:

1.查询效率提升:分区裁剪能减少无关数据的扫描

2.数据维护:支持按照分区粒度进行数据管理,比如数据归档、清理等

3.数据分布:按照分区粒度进行数据分布,能够将数据打散到多个节点上,具备良好的可扩展性

本文首先对分区在 OceanBase 的作用进行介绍,接着描述了 OceanBase 中的基础分区方式以及它们的适用场景,最后讨论了 OceanBase 的灵活分区管理能力如何应用于数据维护、数据管理等业务场景。

OceanBase 中分区的作用

在 OceanBase 中,分区是水平分片的基本单位,是数据分布、负载均衡和并行操作的最小物理单元。一张大表被逻辑地分割成多个更小、更易管理的独立块,每个分区(甚至分区的不同副本)都可以分散存储在集群中不同的 OBServer 节点上。

这种设计为分析型业务带来了根本性的优势:当单一节点的存储或计算能力成为瓶颈时,可以通过增加节点并重新分布分区的方式,实现近乎线性的水平扩展,从而处理 PB 级别的数据量。

分区裁剪提升查询效率

使用分区后,指定分区列进行查询时,在某些场景下能够裁剪出满足查询条件的分区,使得查询无须查询那些不满足条件的分区。

参考如下例子,我们在列 c2 上创建 hash 分区,指定 c2=1 的查询条件,能够裁剪出只需要查询分区 p1。

plain 复制代码
-- 创建一张四个hash分区的表格t1,分区键为C2create table t1(c1 int, c2 int) partition by hash(c2) partitions 4;
-- 指定c2=1查询,裁剪出分区p1explain select * from t1 where c2 = 1;+------------------------------------------------------------------------------------+| Query Plan                                                                         |+------------------------------------------------------------------------------------+| ===============================================                                    || |ID|OPERATOR       |NAME|EST.ROWS|EST.TIME(us)|                                    || -----------------------------------------------                                    || |0 |TABLE FULL SCAN|t1  |1       |3           |                                    || ===============================================                                    || Outputs & filters:                                                                 || -------------------------------------                                              ||   0 - output([t1.c1], [t1.c2]), filter([t1.c2 = 1]), rowset=16                     ||       access([t1.c2], [t1.c1]), partitions(p1)                                     ||       is_index_back=false, is_global_index=false, filter_before_indexback[false],  ||       range_key([t1.__pk_increment]), range(MIN ; MAX)always true                  |+------------------------------------------------------------------------------------+

分区裁剪可以过滤掉不需要的数据,但分区数太多可能也会导致其他的问题,例如元数据量过多、分区裁剪的效率可能降低等等,因此,在 OceanBase 的列存表中建议单个分区的行数>=100W 行。

分区作为数据维护单元

在数据库运维中,将分区作为基本的数据维护单元,能较大地简化日常管理流程,例如数据清理场景、分区级收集统计信息等。以数据清理场景为例,当数据按时间进行分区后,清理过期数据就不再需要逐行删除,而是直接通过删除整个历史分区来实现,这种操作仅仅只需要修改元数据,还能彻底释放磁盘空间,避免了传统的 DML 删除操作产生的性能开销。通过分区键(如时间) 将数据自然归类,使维护操作从"逐行扫描"变为"批量处理",极大地提升了管理效率,降低了运维的复杂度。

分区作为数据分布单元

分区作为 OceanBase 的数据分布单元,每个分区的副本可以放置在不同的 OBServer 节点,以实现存储和计算的扩展。

1.存储的扩展:当创建一个分区表时,这些分区及其副本可以根据集群的资源情况,由 OceanBase 自动调度到不同的物理节点上。这意味着单张表的容量不再受限于单机磁盘,而是整个集群的存储容量,当集群的存储空间不足时,通过加节点就能够实现扩展。

2.计算的并行化:这是分析型业务实现高性能的关键因素之一,当一个查询(特别是涉及全表扫描或大规模聚合的查询)被执行时,OceanBase 的优化器会识别出查询涉及的分区。查询任务可以被分解成多个子任务,并下推到各个数据分区所在的节点上并行执行。例如,一个 SUM() 操作会在每个分区本地先计算小计,然后将中间结果汇总得到最终总和,这充分利用了多节点的计算能力,从而显著加速查询。

OceanBase 的基础分区方式

目前 OceanBase 中支持三大类基础的分区方式,包括 Hash/Key,Range/Range Columns 和 List/List Columns,三种分区方式各自的使用场景有所不同。

HASH/KEY 分区

一般适用于分区列 NDV(不同值的种类)较大,且难以划分出明确范围的情况。优点是容易让没有特定规则的数据也能够在不同的分区内均匀分布,缺点是在范围查询时难以进行分区裁剪。

适用场景举例:无明显查询模式,需均匀分布数据到多个节点(如用户ID、交易ID)。

设计要点:

  • 分区键选择:
    • NDV(唯一值数量)远大于分区数(如用户 ID 的 NDV 应远大于分区数)。
    • 优先选择无倾斜(或只有少量倾斜)的整型/时间列(如 user_id, order_time,或者自增列)。
    • 高频查询条件字段(如 user_id 作为 Join 关键字)。
  • 分区数推荐:
    • 确保分区数匹配集群的机器数量,避免资源分配不均衡

示例场景(Hash 分区使用场景)

markdown 复制代码
-- Hash分区,按user_id均匀分布CREATE TABLE customer(  user_id BIGINT NOT NULL,  login_time TIMESTAMP NOT NULL,  customer_name VARCHAR(100) NOT NULL,  phone_num BIGINT NOT NULL,  city_name VARCHAR(50) NOT NULL,  sex INT NOT NULL,  id_number VARCHAR(18) NOT NULL,  home_address VARCHAR(255) NOT NULL,  office_address VARCHAR(255) NOT NULL,  age INT NOT NULL)PARTITION BY HASH(user_id) PARTITIONS 128;
Range/Range Columns 分区

一般适用于分区键容易划分出明确的范围的情况,例如可以把记录流水信息的大表,根据表示信息时间的列做 RANGE 分区。

适用场景举例

  • 数据按时间/数值范围增长(如 order_time, price)。
  • 需快速裁剪历史数据(如仅查询最近一个月数据)。

设计要点

  • 分区键选择:
    • 时间字段(如 order_time)或连续数值字段。
    • 分区边界需与业务查询条件对齐(如按天/月划分)。
  • 分区数推荐
    • 根据数据增长设置分区,例如按照月份分区。

示例场景(ange/Range Columns分区示例)

markdown 复制代码
-- 创建系统日志表,按日志时间进行月度RANGE分区,支持快速查询与数据归档CREATE TABLE system_logs(    log_id BIGINT,    log_date TIMESTAMP NOT NULL,    log_level VARCHAR(10),    source_system VARCHAR(50),    user_id BIGINT,    log_message TEXT,    client_ip VARCHAR(15))-- 主分区:按月RANGE分区,使用日期直接表达分区边界PARTITION BY RANGE COLUMNS(log_date)(    PARTITION p_202001 VALUES LESS THAN ('2020-02-01'),    PARTITION p_202002 VALUES LESS THAN ('2020-03-01'),    PARTITION p_202003 VALUES LESS THAN ('2020-04-01'),    PARTITION p_202004 VALUES LESS THAN ('2020-05-01'),    PARTITION p_202005 VALUES LESS THAN ('2020-06-01'),    PARTITION p_202006 VALUES LESS THAN ('2020-07-01'),    PARTITION p_202007 VALUES LESS THAN ('2020-08-01'),    PARTITION p_202008 VALUES LESS THAN ('2020-09-01'),    PARTITION p_202009 VALUES LESS THAN ('2020-10-01'),    PARTITION p_202010 VALUES LESS THAN ('2020-11-01'),    PARTITION p_202011 VALUES LESS THAN ('2020-12-01'),    PARTITION p_202012 VALUES LESS THAN ('2021-01-01'),    -- 默认分区处理未来数据或时间格式异常的记录    PARTITION p_future VALUES LESS THAN (MAXVALUE));
List/List Columns分区

一般适用于需要显式控制各行数据如何映射到具体的某一个分区时,优点是可以对无序或无关的数据集进行精准分区,缺点是在范围查询时难以进行分区裁剪。

适用场景举例

  • 离散型字段(如地区、渠道类型)。
  • 需按固定类别快速裁剪数据(如查询华东地区用户)。

设计要点

  • 分区键选择:
    • 离散值且数量有限(如 region 字段仅有 ['east','west','south','north'])。
    • 分区值需覆盖所有可能取值,避免遗漏。
  • 分区数限制:
    • 根据业务逻辑进行配置分区数

示例场景(List/List Columns 分区使用场景)

markdown 复制代码
CREATE TABLE orders_by_region(    order_id BIGINT COMMENT '订单唯一标识',    region_code INT NOT NULL PRIMARY KEY  COMMENT '区域代码(1=north/china, 2=east/china, 3=south/china, 4=west/china)',    customer_id BIGINT COMMENT '客户ID',    order_time DATETIME COMMENT '订单创建时间',    product_category VARCHAR(50) COMMENT '商品类别',    order_amount DECIMAL(18,2) COMMENT '订单金额',    payment_status VARCHAR(20) COMMENT '支付状态(如:PAID, UNPAID)')PARTITION BY LIST(region_code)  -- 改为整数类型分区键(    PARTITION p_north VALUES IN (1),  -- 区域代码1对应north/china    PARTITION p_east VALUES IN (2),    PARTITION p_south VALUES IN (3),    PARTITION p_west VALUES IN (4),    PARTITION p_other VALUES IN (DEFAULT)  -- 默认分区处理未知区域);

灵活的分区管理能力

OceanBase 有非常灵活的分区管理能力,从数据管理的角度来看,它既有数据维护的功能,也有数据分布的功能;从使用方式来讲,它有手动管理和自动管理两种方式;从分区的层次来考虑,它支持一级分区和二级分区组合使用,通过不同的组合,满足用户对于数据管理的不同需求。

本节将从数据维护和数据分布来个角度来展开,同时在两个角度中考虑使用方式以及分区的层次的能力组合。

数据维护

业务层通常按照时间维度来管理分区,方便做数据的归档,清理等操作,我们从业务的完整的数据生命周期流程来结合来描述我们的手动分区管理能力。

1.业务建表:创建按照时间分区的表格,提前创建未来一段时间需要的分区

2.业务导数:导入数据

3.业务运行:随着时间的推进,可能提前创建的分区不足,继续提前创建未来一段时间需要的分区

4.定期数据清理:当数据积累到一定时间后,可能之前的数据就不需要了,此时可以删除不需要的分区

以下是上述使用场景的具体例子:

markdown 复制代码
-- 1. 创建分区表(按天分区,预创建未来7天分区)CREATE TABLE business_data(    id BIGINT NOT NULL AUTO_INCREMENT,    event_time DATETIME NOT NULL,    metric_value DECIMAL(10,2),    PRIMARY KEY (id, event_time)) PARTITION BY RANGE COLUMNS(event_time)(    PARTITION p20231025 VALUES LESS THAN ('2023-10-26'),    PARTITION p20231026 VALUES LESS THAN ('2023-10-27'),    PARTITION p20231027 VALUES LESS THAN ('2023-10-28'),    PARTITION p20231028 VALUES LESS THAN ('2023-10-29'),    PARTITION p20231029 VALUES LESS THAN ('2023-10-30'),    PARTITION p20231030 VALUES LESS THAN ('2023-10-31'),    PARTITION p20231031 VALUES LESS THAN ('2023-11-01')  -- 预创建未来7天分区);-- 2. 导入数据,这里略过-- 3. 预创建未来7天分区ALTER TABLE business_data ADD PARTITION(  PARTITION p20231101 VALUES LESS THAN ('2023-11-02'),  PARTITION p20231102 VALUES LESS THAN ('2023-11-03'),  PARTITION p20231103 VALUES LESS THAN ('2023-11-04'),  PARTITION p20231104 VALUES LESS THAN ('2023-11-05'),  PARTITION p20231105 VALUES LESS THAN ('2023-11-06'),  PARTITION p20231106 VALUES LESS THAN ('2023-11-07'),  PARTITION p20231107 VALUES LESS THAN ('2023-11-08'));-- 4. 定期数据清理,例如数据到期后,删除7天的数据ALTER TABLE business_data DROP PARTITION p20231025, p20231026, p20231027, p20231028, p20231029, p20231030, p20231031;

由于数据在不停地写入,手工维护预创建分区和定期清理分区还是比较麻烦的。为了简化这个流程,OceanBase 提供了动态分区功能,支持按固定时间分区,预创建多长时间的分区和保留多久的历史分区等功能,对于上面的例子,假如我们需要保留 30 天数据,每次预创建 7 天的分区,那么使用如下语法来进行创建:

markdown 复制代码
-- 1. 创建分区表,设置动态分区策略CREATE TABLE t1(    id BIGINT NOT NULL AUTO_INCREMENT,    event_time DATETIME NOT NULL,    metric_value DECIMAL(10,2),    PRIMARY KEY (id, event_time))DYNAMIC_PARTITION_POLICY(  ENABLE = true,  TIME_UNIT = 'day',  PRECREATE_TIME = '7day',  EXPIRE_TIME = '30day')PARTITION BY RANGE COLUMNS(event_time)(  PARTITION p20231025 VALUES LESS THAN ('2023-10-26'));

除了 Range 分区模式外,业务也可以按照业务需求选择其他基础分区方式。

数据分布

分区也可以作为数据据分布管理的单元,通常情况下为了数据打散,一般使用 HASH 分区的方式,它有如下优势:

  1. 它通常能实现比较好的数据打散的需求,也能够做比较准确的分区裁剪;
  2. 对于需要 join 的多张表格,如果按照 join 键进行 hash 分区,并且分区数也保持一致,此时配合 OceanBase table group 能力,能够实现相同 hash 规则的对应下标的分区绑定在一起,从而使得 join 时能够使用 Partition Wised Join,避免数据 shuffle。

Hash 分区也存在部分问题:

  1. Hash 分区的分区数设置之后,修改分区数是一个比较重的操作,涉及到整张表的数据重写,所以,一般设置好 Hash 分区的分区数之后,就一般不再变化,比较难以实现可扩展;
  2. 对于分区键上的范围查询,无法裁剪出分区,需要访问所有的分区,可能会存在读放大。

为了解决 HASH 分区可扩展性以及范围查询的问题,OceanBase 已经支持行存表的自动分区分裂能力,在未来版本中还将提供两种列存表自动分区分裂的模式:堆表分区分裂模式和聚集索引(clustering key)表分区分裂模式。

堆表分区分裂模式基于堆表的隐藏主键列进行自动分区,由于隐藏主键在分区分裂模式下是随机生成的,并且当租户的机器资源扩展或缩容时,会自动扩充或者缩减对应的分区数,使得该模式能够自动地进行扩展,具备比较好的可扩展性。不过,该模式下数据行是随机分布在任意一个分区的,因此是无法进行分区裁剪的,所以查询性能上可能不是最优,该模式适合对性能要求不高,且不希望提供手动分区或者自动分区键的情况,但又希望表能够自动地扩展。

聚集索引表分区分裂模式基于用户指定的聚集键进行自动分区,按照数据量进行自动地切分合适大小的分区,当租户的机器资源扩展或者缩容时,由于分裂的分区数已经足够多时,就可以将这些分区重新进行均衡。该模式由于按照聚集键进行自动拆分,当查询能够指定聚集键查询,无论是点查还是范围查询,能够进行分区裁剪,查询性能是比较优的,并且也能够根据机器资源进行自适应地扩展或者缩容。同时聚集索引表自动分裂也能够对支持多张需要 join 的表配置 table group,其中自动分裂的键可以配置为 join键,也能实现 Partition Wised Join。

为了方便大家理解,Hash、堆表分区分裂和聚集索引表分区分裂三种方式的特点对比如下:

除了上述分区方式,业务也可以按照业务需求选择其他的基础分区方式。

混合数据维护和数据分布管理

我们也可以以二级分区的方式,同时支持数据维护和数据分布的需求,通常使用比较多的场景为一级分区用于数据维护的需求,二级分区用于数据分布的需求,每种需求可以使用对应需求所支持的方式进行组合。

典型的手动分区管理方式
  1. 一级分区:
    • 类型选择:使用 Range 或者 List 分区,匹配高频查询条件(如时间范围、地区)。
    • 分区数建议:根据查询条件时间分布、数据维护的需求设置合理范围(如按月分区保留 12 个月,或按地区分为 4 个 List 分区)。
  2. 二级分区:
    • 类型选择: 使用Hash分区,保证数据打散。
    • 分区数推荐:
      • 如果只有一个一级分区写入,那么一级分区的二级分区数需要满足写入打散的资源诉求
      • 如果有多个一级分区能够写入,那么能写入的一级分区数 * 二级分区数满足写入打散的资源诉求即可

以下是 Range + Hash 和 List + Hash 的两个场景案例:

1.Range + Hash:一级选择 Range 分区,指定 order_date 后,可以快速过滤掉不需要扫描数据的分区,也能够通过分区管理操作快速进行数据维护,二级选择 Hash 分区,可以将当月的写入或者读取打散到 8 个分区中,避免热点。

markdown 复制代码
CREATE TABLE orders(    user_id BIGINT NOT NULL COMMENT '用户ID(二级分区键)',    order_date DATE NOT NULL COMMENT '下单日期(一级分区键)',    amount DECIMAL(10,2) NOT NULL COMMENT '订单金额',    status TINYINT NOT NULL COMMENT '状态: 0-取消 1-待支付 2-已支付 3-已发货 4-已完成',    region_code CHAR(6) NOT NULL COMMENT '地区编码(前2位省码)',    product_id INT NOT NULL COMMENT '商品ID',    payment_method VARCHAR(20) COMMENT '支付方式',    created_at TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP(6) COMMENT '记录创建时间')PARTITION BY RANGE COLUMNS(order_date)SUBPARTITION BY HASH(user_id) SUBPARTITIONS 8(  PARTITION p202501 VALUES LESS THAN ('2025-02-01'),  PARTITION p202502 VALUES LESS THAN ('2025-03-01'),  ...  PARTITION p202601 VALUES LESS THAN ('2026-02-01'));

2.List + Hash:一级选择 List 分区,指定省份能够裁剪到相应的分区,也可以按照省维度进行数据维护,二级选择 Hash/Key 分区,可以将省的读写流量打散到多个分区中,实现负载均衡。

markdown 复制代码
-- 一级分区:LIST按省划分(31个省级行政区)CREATE TABLE social_insurance_records(    record_id BIGINT,    province_code INT NOT NULL,  -- 省级编码(如11北京,31上海)    payment_date DATE NOT NULL,    user_id VARCHAR(32) NOT NULL,    amount DECIMAL(10,2)) PARTITION BY LIST(province_code)  -- 一级LIST分区SUBPARTITION BY KEY(user_id) SUBPARTITIONS 16  -- 二级HASH分区(  PARTITION p_beijing VALUES IN (11),  PARTITION p_shanghai VALUES IN (31),  PARTITION p_tianjin VALUES IN (12),  ...  PARTITION p_xizang VALUES IN (54));

典型的自动分区管理方式

  1. 一级分区:选择动态分区,配置按固定时间分区,预创建多长时间的分区和保留多久的历史分区等参数;
  2. 二级分区:选择自动 Range 分区分裂,能够自动地进行分裂,无须配置分区个数或者分区规则。

总结

目前 OceanBase 支持了常见的基础分区方式,通过基础分区方式的组合使用,能够满足业务的数据维护、数据分布以及提升查询效率等需求。动态分区对按照时间进行分区数据维护的通用需求提供了标准的自动化管理能力,减少用户对数据维护的代价,未来我们将加强自动分区的管理能力,支持列存表的自动分区分裂,减少当前数据分布手工维护的代价、可扩展性等问题,进一步提升列存表的数据管理自动化管理能力,使得分析型业务场景能更容易使用OceanBase。

相关推荐
胖头鱼的鱼缸(尹海文)5 天前
数据库管理-第386期 使用OCP部署OceanBase 4.4.1社区版集群(20251107)
数据库·oceanbase
kpli908 天前
OceanBase数据库SQL调优
数据库·sql·oceanbase
IDOlaoluo9 天前
OceanBase all-in-one 4.2.0.0 安装教程(CentOS 7/EL7 一键部署详细步骤)
linux·centos·oceanbase
少年攻城狮10 天前
OceanBase系列---【如何拆分PMAX分区?】
oceanbase
老纪的技术唠嗑局12 天前
分库分表MyCat 架构迁移 OceanBase | 百丽核心财务系统迁移经验总结与问题汇总
数据库·架构·oceanbase
GottdesKrieges13 天前
OceanBase集群诊断工具:obdiag
数据库·sql·oceanbase
少年攻城狮13 天前
OceanBase系列---【如何把一个表改造成分区表?】
数据库·sql·oceanbase
观测云14 天前
阿里云 OceanBase 可观测最佳实践
阿里云·云计算·oceanbase