---
title: "AP 场景下的表分区设计实践 - OceanBase 数据库 V4.6.0 | OceanBase 文档中心"
description: AP 场景下的表分区设计实践 分析型业务通常需要对海量数据进行分析计算，这对数据库的查询能力以及数据管理能力都有很高的要求。OceanBase 通过分区技术，将一张表的数据按照分区键水平拆分成多个数据子集，有助于查询效率提升和数据管理能力： 查询效率提升： 分区裁剪能减少无关数据的扫描。 数据维护： 支持按照分区粒度…
---
切换语言

- 中文站 - 简体中文
- International - English
- 日本站 - 日本語

文档反馈![](https://mdn.alipayobjects.com/huamei_22khvb/afts/img/A*P8CuR4UJ_FkAAAAAAAAAAAAADiGDAQ/original) OceanBase 数据库分布式版 - V 4.6.0

# AP 场景下的表分区设计实践

更新时间：2026-06-20 12:56:43

[编辑](https://github.com/oceanbase/oceanbase-doc/edit/V4.6.0/zh-CN/620.obap/200.obap-data-design/800.data-design-best-practice/300.best-practice-table-partition.md)  

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

- **查询效率提升：** 分区裁剪能减少无关数据的扫描。
 - **数据维护：** 支持按照分区粒度进行数据管理，比如数据归档、清理等。
 - **数据分布：** 按照分区粒度进行数据分布，能够将数据打散到多个节点上，具备良好的可扩展性。

## 分区的作用

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

这种设计为分析型业务带来了根本性优势：当单个节点的存储或计算能力达到瓶颈时，只需通过增加节点并重新分布分区，即可实现近乎线性的水平扩展，轻松应对 PB 级数据规模。

## 分区裁剪提升查询效率

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

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

```sql
-- 创建一张四个 hash 分区的表格 t1，分区键为 C2
CREATE TABLE t1(c1 INT, c2 INT) PARTITION BY HASH(c2) PARTITIONS 4;

-- 指定 c2 = 1 查询，裁剪出分区 p1
EXPLAIN SELECT * FROM t1 WHERE c2 = 1;

```

执行计划输出显示：

```sql
+------------------------------------------------------------------------------------+
| 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 的列存表中建议单个分区的行数 ≥ 100 W 行。

## 分区作为数据维护单元

在数据库运维中，将分区作为基本的数据维护单元，能较大地简化日常管理流程，例如数据清理场景、分区级收集统计信息等。

以**数据清理**场景为例，当数据按时间进行分区后，清理过期数据就不再需要逐行删除，而是直接通过删除整个历史分区来实现。这种操作仅仅只需要修改元数据，还能彻底释放磁盘空间，避免了传统的 DML 删除操作产生的性能开销。

通过分区键（如时间）将数据自然归类，使维护操作从 “逐行扫描” 变为 “批量处理”，极大地提升了管理效率，降低了运维的复杂度。

## 分区作为数据分布单元

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

- **存储的扩展：** 当创建一个分区表时，这些分区及其副本可以根据集群的资源情况，由 OceanBase 自动调度到不同的物理节点上。这意味着单张表的容量不再受限于单机磁盘，而是整个集群的存储容量。当集群的存储空间不足时，通过加节点就能够实现扩展。
 - **计算的并行化：** 这是分析型业务实现高性能的关键因素之一。当一个查询（特别是涉及全表扫描或大规模聚合的查询）被执行时，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 关键字）。
 - **分区数推荐：**

     - 确保分区数匹配集群的机器数量，避免资源分配不均衡

**示例场景：**

```sql
-- 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`）或连续数值字段。
     - 分区边界需与业务查询条件对齐（如按天 / 月划分）。
 - **分区数推荐：**

     - 根据数据增长设置分区，例如按照月份分区。

**示例场景：**

```sql
-- 创建系统日志表，按日志时间进行月度 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']`）。
     - 分区值需覆盖所有可能取值，避免遗漏。
 - **分区数限制：**

     - 根据业务逻辑进行配置分区数。

**示例场景：**

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

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

### 数据维护

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

- **业务建表：** 创建按照时间分区的表格，提前创建未来一段时间需要的分区。
 - **业务导数：** 导入数据。
 - **业务运行：** 随着时间的推进，可能提前创建的分区不足，继续提前创建未来一段时间需要的分区。
 - **定期数据清理：** 当数据积累到一定时间后，可能之前的数据就不需要了，此时可以删除不需要的分区。

**示例：**

```sql
-- 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 天的分区，那么使用如下语法进行创建：

```sql
-- 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 分区模式外，业务也可以按照业务需求选择其他基础分区方式。

更多关于动态分区的信息，可参见[动态分区](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005682068)、[MySQL 模式下创建动态分区表](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005685868) 和 [Oracle 模式下创建动态分区表](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005685844)

### 数据分布

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

- 它通常能有效实现数据的均匀分布，并支持基于分区键的精确分区裁剪。
 - 对于需要进行 JOIN 操作的多张表，若均以相同的 JOIN 键进行 HASH 分区，且分区数量一致，再结合 OceanBase 的 Table Group 功能，可将各表中哈希值相同的分区绑定到同一组节点上，从而在执行 JOIN 时启用 Partition-Wise Join，避免跨节点的数据 Shuffle，显著提升查询性能。

**Hash 分区也存在限制：**

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

为了解决 HASH 分区可扩展性以及范围查询的问题，OceanBase 已经支持行存表的自动分区分裂能力。

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

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

### 典型的手动分区管理方式

- **一级分区：**
     - 类型选择：使用 Range 或者 List 分区，匹配高频查询条件（如时间范围、地区）
     - 分区数建议：根据查询条件时间分布、数据维护的需求设置合理范围（如按月分区保留 12 个月，或按地区分为 4 个 List 分区）
 - **二级分区：**
     - 类型选择：使用 Hash 分区，保证数据打散
     - 分区数推荐：
           - 如果只有一个一级分区写入，那么一级分区的二级分区数需要满足写入打散的资源诉求
           - 如果有多个一级分区能够写入，那么能写入的一级分区数 × 二级分区数满足写入打散的资源诉求即可

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

#### Range + Hash

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

```sql
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')
);

```

#### List + Hash

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

```sql
-- 一级分区：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 分区分裂，能够自动地进行分裂，无须配置分区个数或者分区规则

## 相关文档

- **MySQL 模式：**

     - [动态分区概述](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005685869)
     - [创建动态分区表](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005685868)
     - [查看动态分区表](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005685870)
     - [修改动态分区表](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005685867)
 - **Oracle 模式：**

     - [动态分区概述](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005685846)
     - [创建动态分区表](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005685844)
     - [查看动态分区表](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005685848)
     - [修改动态分区表](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005685847)

 上一篇 下一篇 ![有帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*y6ocSqN8cqsAAAAAAAAAAAAAARQnAQ)![无帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*BG9IQJyLHF8AAAAAAAAAAAAAARQnAQ)![反馈](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*eTWdQKCRKHwAAAAAAAAAAAAAARQnAQ)[AI](https://www.oceanbase.com/obi) 咨询热线
