分区类别简介

按照数据分区的规则,分为如下三类:

  • hash/key

  • range/range columns

  • list/list columns

按照分区划分的维度。可以分为如下两类:

  • 一级分区
  • 二级分区

一级分区只有一个分区键,二级分区有两个分区键。

如下图所示,按照两个分区键 user_id, create_time 进行分区:

image

分区选择原则

大表选择水平分区能在某些情况下改善查询性能、均衡 IO、增强可用性和可维护性,在选择分区的方式上可以参考如下建议:

  • Range 分区适合处理相似的、与时间有关的数据,或者需要定期导入新数据删除历史数据的场景;
  • Hash 分区适合随机分布的数据,hash 算法会将分区列的数据进行重分布使得相近的值被打散到不同分区,如销售记录表以商品编号进行 Hash 分区;
  • List 分区适合分区值明确的情形,如顾客信息表中以区域字段作为 List 分区列。

Hash分区

Hash 分区需要指定分区键和分区个数。通过 hash 的分区表达式计算得到一个 int 类型的结果,这个结果再跟分区个数取模得到具体这行数据属于那个分区。通常用于给定分区键的点查询,例如按照用户 id 来分区。Hash 分区通常能消除热点查询。
如下例所示:
create table t1 (c1 int, c2 int) partition by hash(c1 + 1) partitions 5
其中 partition by hash(c1+1) 指定了分区键c1和分区表达式 c1 + 1;partitions 5 指定了分区数;对于(1,2)这行数据来说,它的属于(1 + 1) % 5 = 2号分区。

Hash分区的限制和要求如下:

  • 分区表达式的结果必须是 int 类型
  • 不能写向量,例如 partition by hash(c1, c2)

Key分区

key 分区跟 Hash 分区类似,也是通过对分区个数取模的方式来确定数据属于哪个分区。不同的是系统会对 key 分区键做一个内部默认的 Hash 函数后再取模。所以用户通常没有办法自己通过简单的计算来得知某一行属于哪个分区。
如下例所示:
create table t1 (c1 int, c2 int) partition by key(c1) partitions 5

对于非字符串类型,直接使用 murmur hash。对于字符串类型(例如 varchar 和 char 类型),key 分区使用的是 MySQL 的hash 函数。主要原因是字符串的 collation,在某些 collation 里面大小写是相等的,例如‘A’ = ‘a’,所以要求‘A’和‘a’计算的 hash 值相同,所以不能直接用murmur hash。

MySQL 的 key 分区的 hash 函数不太均匀,不同如下:

  • key 分区不要求是int类型,可以是任意类型
  • key 分区不能写表达式,hash 分区可以写表达式
  • key 分区支持向量
  • key 分区有一个特殊的语法

create table t1 (c1 int primary key, c2 int) partition by key() partitions 5
key 分区 list 不写任何 column,表示 key 分区的列是主键。

Range分区

Range 分区是按照分区表达式的范围来划分分区。通常用于对分区键需要按照范围的查询。例如通过按照时间字段进行范围分区,还有价格区间等一些分区方式。
create table t1 (c1 int, c2 int) partition by range(c1) (partition p0 values less than(100), partition p1 values less than(500), partition p2 values less than(maxvalue));
p0, p1, p2 表示range的访问分别是(min, 100), [100, 500), [500, max) 的范围。

Range分区的限制和要求如下:

  • 分区表达式的结果可以是 int 类型或 datatime 类型
  • 不能写向量,例如 partition by range (c1, c2)

Range 分区的操作说明

目前提供对 Range 分区的分区操作功能为 add/drop 分区。add 分区现在只能加在最后,所以最后不能是 maxvalue 的分区。如果是 maxvalue 的分区要增加一个分区,只能做分区分裂。现在还不支持分区分裂。

Range columns分区

Range columns 分区和 Range分区的区别是:

  • range columns 分区不要求是 int 类型,可以是任意类型
  • range columns 分区不能写表达式
  • range columns 分区支持向量

List分区

List 分区是根据枚举类型的值来划分分区的,主要用于枚举类型。

如下例所示,这个表分区的含义是当某一行的 c1 = 1 or c1 = 2 or c1 = 3 的时候,那么这一行属于分区 p0,当 c1 = 5 or c1 = 6 的时候,那么这一行属于分区 p1。除此之外都所有行都属于 p2。

create table t1 (c1 int, c2 int) partition by list(c1) (partition p0 values in (1,2,3), partition p1 values in (5, 6), partition p2 values in (default));

List分区的限制和要求如下:

  • 分区表达式的结果必须是int类型
  • 不能写向量,例如partition by list(c1, c2)

List columns分区

List columns 和 list 的区别是:

  • list columns分区不要求是int类型,可以是任意类型
  • list columns分区不能写表达式
  • list columns分区支持向量

二级分区简介

二级分区是指按照两个维度来把数据拆分成分区。
最常用的地方就是类似用户账单领域,会按照 user_id 做 hash 分区,按照账单创建时间做 range 分区。

  • hash/key + range/range columns 分区

  • range/range columns + hash/key 分区

  • list + range/range columns 分区

  • range/range columns + list 分区

  • hash/key + list 分区

  • list+hash/key 分区

注意:
Oracle 的二级分区支持每个一级分区的二级分区,分区定义不一样。

如下例所示,一级分区 p0 下面有一个分区,而一级分区 p1 下面有两个分区。

create table t1 (c1 int, c2 int) partition by range(c1) subpartition by hash(c2) (partition p0 values less than(100) (subpartition sp0), partition p1 values less than(200) (subpartition sp2, subpartition sp3));

OceanBase 暂时不支持这样的分区方式,必须用 template 的分区方式。

这导致对于 range 分区的分区操作 add/drop,必须是 range 分区做为一级分区的方式。所以强烈建议用 range + hash 的分区方式,而不是 hash + range。