分区策略 
=========================



OceanBase 支持多种分区策略：

* 范围（RANGE）分区

  

* RANGE COLUMNS 分区

  

* 列表（LIST）分区

  

* LIST COLUMNS 分区

  

* 哈希（HASH）分区

  

* 组合分区

  




范围（RANGE）分区 
--------------------

RANGE 分区根据分区表定义时为每个分区建立的分区键值范围，将数据映射到相应的分区中。它是常见的分区类型，经常跟日期类型一起使用。比如说，可以将业务日志表按日/周/月分区。RANGE 分区简单的语法格式如下：

```javascript
CREATE TABLE table_name (
    column_name1        column_type
    [, column_nameN     column_type]
) PARTITION BY RANGE ( expr(column_name1) )
(
    PARTITION   p0      VALUES LESS THAN ( expr )
    [, PARTITION pN     VALUES LESS THAN (expr ) ]
 [, PARTITION pX    VALUES LESS THAN (maxvalue) ]
);
```



当使用 RANGE 分区时，需要遵守如下几个规则：

* PARTITION BY RANGE ( expr ) 里的 expr 表达式的结果必须为整形。

  

* 每个分区都有一个 VALUES LESS THAN 子句，它为分区指定一个非包含的上限值。分区键的任何值等于或大于这个值时将被映射到下一个分区中。

  

* 除第一个分区外，所有分区都隐含一个下限值，即上一个分区的上限值。

  

* 允许且只允许最后一个分区上限定义为 MAXVALUE ，这个值没有具体的数值，比其他所有分区的上限都要大，也包含空值。

  




示例：创建一个 RANGE 分区表。

```javascript
CREATE TABLE t_log_part_by_range (
    log_id      bigint NOT NULL 
    , log_value varchar(50)
    , log_date  timestamp NOT NULL  
) PARTITION BY RANGE(UNIX_TIMESTAMP(log_date)) 
(
    PARTITION M202001 VALUES LESS THAN(UNIX_TIMESTAMP('2020/02/01'))
    , PARTITION M202002 VALUES LESS THAN(UNIX_TIMESTAMP('2020/03/01'))
    , PARTITION M202003 VALUES LESS THAN(UNIX_TIMESTAMP('2020/04/01'))
    , PARTITION M202004 VALUES LESS THAN(UNIX_TIMESTAMP('2020/05/01'))
    , PARTITION M202005 VALUES LESS THAN(UNIX_TIMESTAMP('2020/06/01'))
    , PARTITION M202006 VALUES LESS THAN(UNIX_TIMESTAMP('2020/07/01'))
    , PARTITION M202007 VALUES LESS THAN(UNIX_TIMESTAMP('2020/08/01'))
    , PARTITION M202008 VALUES LESS THAN(UNIX_TIMESTAMP('2020/09/01'))
    , PARTITION M202009 VALUES LESS THAN(UNIX_TIMESTAMP('2020/10/01'))
    , PARTITION M202010 VALUES LESS THAN(UNIX_TIMESTAMP('2020/11/01'))
    , PARTITION M202011 VALUES LESS THAN(UNIX_TIMESTAMP('2020/12/01'))
    , PARTITION M202012 VALUES LESS THAN(UNIX_TIMESTAMP('2021/01/01'))
);
```



RANGE 分区可以新增、删除分区。如果最后一个 RANGE 分区指定了 MAXVALUE ，则不能新增分区。

RANGE 分区要求表拆分键表达式的结果必须为整型，如果要按时间类型列做 RANGE 分区，则必须使用 timestamp 类型，并且使用函数 UNIX_TIMESTAMP 将时间类型转换为数值。这个需求也可以使用 RANGE COLUMNS 分区实现，就没有整型这个要求。

RANGE COLUMNS 分区 
-------------------------

RANGE COLUMNS 分区作用跟 RANGE 分区基本类似，不同之处在于：

* RANGE COLUMNS 拆分列结果不要求是整型，可以是任意类型。

  

* RANGE COLUMNS 拆分列不能使用表达式。

  

* RANGE COLUMNS 拆分列可以写多个列（即列向量）。

  




RANGE COLUMNS 分区的简单语法格式如下：

```javascript
CREATE TABLE table_name (
    column_name1        column_type
    [, column_nameN     column_type]
) PARTITION BY RANGE ( column_name1 [, column_name2] )
(
    PARTITION   p0      VALUES LESS THAN ( expr )
    [, PARTITION pN     VALUES LESS THAN (expr ) ]
[, PARTITION pX VALUES LESS THAN (maxvalue) ]
);
```



示例：创建一个 RANGE COLUMNS 分区

```javascript
CREATE TABLE t_log_part_by_range_columns (
    log_id      bigint NOT NULL 
    , log_value varchar(50)
    , log_date  date NOT NULL  
) PARTITION BY RANGE COLUMNS(log_date) 
(
    PARTITION M202001 VALUES LESS THAN('2020/02/01')
    , PARTITION M202002 VALUES LESS THAN('2020/03/01')
    , PARTITION M202003 VALUES LESS THAN('2020/04/01')
    , PARTITION M202004 VALUES LESS THAN('2020/05/01')
    , PARTITION M202005 VALUES LESS THAN('2020/06/01')
    , PARTITION M202006 VALUES LESS THAN('2020/07/01')
    , PARTITION M202007 VALUES LESS THAN('2020/08/01')
    , PARTITION M202008 VALUES LESS THAN('2020/09/01')
    , PARTITION M202009 VALUES LESS THAN('2020/10/01')
    , PARTITION M202010 VALUES LESS THAN('2020/11/01')
    , PARTITION M202011 VALUES LESS THAN('2020/12/01')
    , PARTITION M202012 VALUES LESS THAN('2021/01/01')
    , PARTITION MMAX VALUES LESS THAN MAXVALUE
);
```



列表（LIST）分区 
-------------------

LIST 分区使得您可以显式的控制记录行如何映射到分区，具体方法是为每个分区的分区键指定一组离散值列表，这点跟 RANGE 分区和 HASH 分区都不同。LIST 分区的优点是可以方便的对无序或无关的数据集进行分区。LIST 分区的简单语法格式如下：

```javascript
CREATE TABLE table_name (
    column_name1        column_type
    [, column_nameN     column_type]
) PARTITION BY LIST ( expr(column_name1) )
(
    PARTITION   p0      VALUES IN ( v01 [, v0N] )
    [, PARTITION pN     VALUES IN ( vN1 [, vNN] ) ]
 [, PARTITION pX    VALUES IN (default) ]
);
```



当使用列表分区时，需要遵守以下规则：

* 分区表达式结果必须是整型。

  

* 分区表达式只能引用一列，不能有多列（即列向量）。

  




示例：创建一个 LIST 分区表。

```javascript
CREATE TABLE t_part_by_list ( 
    c1 BIGINT PRIMARY KEY
    , c2 VARCHAR(50)
) PARTITION BY list(c1) 
( 
    PARTITION p0    VALUES IN (1, 2, 3)
    , PARTITION p1  VALUES IN (5, 6)
    , PARTITION p2  VALUES IN (DEFAULT)
);
```



LIST 分区可以新增分区，指定新的不重复的列表。也可以删除分区。

LIST COLUMNS 分区 
------------------------

LIST COLUMNS 分区作用跟 LIST 分区基本相同，不同之处在于：

* LIST COLUMNS 的拆分列不能是表达式。

  

* LIST COLUMNS 的拆分列可以是多列（即列向量）。

  




LIST COLUMNS 分区简单的语法格式如下：

```javascript
CREATE TABLE table_name (
    column_name1        column_type
    [, column_nameN     column_type]
) PARTITION BY LIST COLUMNS ( column_name1 [, column_nameN ] )
(
    PARTITION   p0      VALUES IN ( v01 [, v0N] )
    [, PARTITION pN     VALUES IN ( vN1 [, vNN] ) ]
 [, PARTITION pX    VALUES IN (default) ]
);
```



示例：创建一个 LIST COLUMNS 分区

```javascript
CREATE TABLE t2 (
  id varchar(64),
  type varchar(16),
  info varchar(512),
  gmt_create datetime(6),
  gmt_modified datetime(6),
  partition_id varchar(2) GENERATED ALWAYS AS (substr(`id`,19,20)) VIRTUAL,
  PRIMARY KEY (id)
) partition by list columns(partition_id)
(partition p0 values in ('00','01'),
partition p1 values in ('02','03'),
partition p2 values in (default));
```



哈希（HASH）分区 
-------------------

HASH 分区适合于对不能用 RANGE 分区、LIST 分区方法的场景，它的实现方法简单，通过对分区键上的 HASH 函数值来散列记录到不同分区中。如果您的数据符合下列特点，使用 HASH 分区是个很好的选择：

* 不能指定数据的分区键的列表特征。

  

* 不同范围内的数据大小相差非常大，并且很难手动调整均衡。

  

* 使用 RANGE 分区后数据聚集严重。

  

* 并行 DML、分区剪枝和分区连接等性能非常重要。

  




示例：创建一个 HASH 分区表。

```javascript
CREATE TABLE ware(
    w_id int
    , w_ytd number(12,2)
    , w_tax number(4,4)
    , w_name varchar(10)
    , w_street_1 varchar(20)
    , w_street_2 varchar(20)
    , w_city varchar(20)
    , w_state char(2)
    , w_zip char(9)
    , primary key(w_id)
) PARTITION by hash(w_id) partitions 60;
```



HASH 分区不适合做删除操作。

组合分区 
-------------

组合分区通常是先使用一种分区策略，然后在子分区再使用另外一种分区策略，适合于业务表的数据量非常大时。使用组合分区能发挥多种分区策略的优点。

在指定二级分区分区策略细节时，可以使用 SUBPARTITION TEMPLATE 子句。

示例：创建组合分区表。

```javascript
CREATE TABLE t_ordr_part_by_hash_range (o_w_id int
, o_d_id int
, o_id int
, o_c_id int
, o_carrier_id int
, o_ol_cnt int
, o_all_local int
, o_entry_d TIMESTAMP NOT NULL
, index idx_ordr(o_w_id, o_d_id, o_c_id, o_id) LOCAL 
, primary key ( o_w_id, o_d_id, o_id, o_entry_d )
)  
PARTITION BY hash(o_w_id) 
SUBPARTITION BY RANGE(UNIX_TIMESTAMP(o_entry_d))
SUBPARTITION template
(
    SUBPARTITION M202001 VALUES LESS THAN(UNIX_TIMESTAMP('2020/02/01'))
    , SUBPARTITION M202002 VALUES LESS THAN(UNIX_TIMESTAMP('2020/03/01'))
    , SUBPARTITION M202003 VALUES LESS THAN(UNIX_TIMESTAMP('2020/04/01'))
    , SUBPARTITION M202004 VALUES LESS THAN(UNIX_TIMESTAMP('2020/05/01'))
    , SUBPARTITION M202005 VALUES LESS THAN(UNIX_TIMESTAMP('2020/06/01'))
    , SUBPARTITION M202006 VALUES LESS THAN(UNIX_TIMESTAMP('2020/07/01'))
    , SUBPARTITION M202007 VALUES LESS THAN(UNIX_TIMESTAMP('2020/08/01'))
    , SUBPARTITION M202008 VALUES LESS THAN(UNIX_TIMESTAMP('2020/09/01'))
    , SUBPARTITION M202009 VALUES LESS THAN(UNIX_TIMESTAMP('2020/10/01'))
    , SUBPARTITION M202010 VALUES LESS THAN(UNIX_TIMESTAMP('2020/11/01'))
    , SUBPARTITION M202011 VALUES LESS THAN(UNIX_TIMESTAMP('2020/12/01'))
    , SUBPARTITION M202012 VALUES LESS THAN(UNIX_TIMESTAMP('2021/01/01'))
    , SUBPARTITION MMAX VALUES LESS THAN MAXVALUE
)
partitions 16;

CREATE TABLE t_log_part_by_range_hash (
    log_id      int NOT NULL 
    , log_value varchar(50)
    , log_date  TIMESTAMP NOT NULL 
    , PRIMARY key(log_id, log_date)
) PARTITION BY RANGE(UNIX_TIMESTAMP(log_date))
SUBPARTITION BY HASH(log_id) SUBPARTITIONS 16
(
    PARTITION M202001 VALUES LESS THAN(UNIX_TIMESTAMP('2020/02/01'))
    , PARTITION M202002 VALUES LESS THAN(UNIX_TIMESTAMP('2020/03/01'))
    , PARTITION M202003 VALUES LESS THAN(UNIX_TIMESTAMP('2020/04/01'))
    , PARTITION M202004 VALUES LESS THAN(UNIX_TIMESTAMP('2020/05/01'))
    , PARTITION M202005 VALUES LESS THAN(UNIX_TIMESTAMP('2020/06/01'))
    , PARTITION M202006 VALUES LESS THAN(UNIX_TIMESTAMP('2020/07/01'))
    , PARTITION M202007 VALUES LESS THAN(UNIX_TIMESTAMP('2020/08/01'))
    , PARTITION M202008 VALUES LESS THAN(UNIX_TIMESTAMP('2020/09/01'))
    , PARTITION M202009 VALUES LESS THAN(UNIX_TIMESTAMP('2020/10/01'))
    , PARTITION M202010 VALUES LESS THAN(UNIX_TIMESTAMP('2020/11/01'))
    , PARTITION M202011 VALUES LESS THAN(UNIX_TIMESTAMP('2020/12/01'))
    , PARTITION M202012 VALUES LESS THAN(UNIX_TIMESTAMP('2021/01/01'))
    , PARTITION MMAX VALUES LESS THAN MAXVALUE
);
```



