CO_HASH分区

版本要求

PolarDB-X版本必须为5.4.18-17047709及以上。

适用场景

在电商场景,业务订单表常常会出现以下现象:业务订单表的两个列或多个列之间的值存在一种协同关系,比如,常见的订单表的order_id与buyer_id的后N位数字总是相同的。由于业务订单表的数据量一般偏大,用户考虑在对订单表进行水平切分时,能让订单表同时按order_id或buyer_id的后N位数字进行水平切分。这样业务应用在一些下单场景的事务中,应用无论是从order_id=维度读写还是buyer_id=?维度进行读写,均能路由到同一个物理分区,从而避免出现大量的跨库事务。

那么,PolarDB-X的CO_HASH分区策略就是专用来帮助业务解决上述场景所碰到的分区问题:

  • 分区表的多个分区列的取值之间存在特殊的协同关系(比如,后N位的数值相同、前N位的数据相同,等等 );

  • 分区表支持同时按多个不同的分区列进行独立路由(即这些分区列之间没有前缀关系,查询单独带上各个分区列的等值查询条件均能进行分区裁剪);

语法

要求PolarDB-X支持同时按多个不同的分区列的不同取值进行路由。

CREATE TABLE ... 
PARTITION BY CO_HASH(partition_expr_list) 
PARTITIONS number;

partition_expr_list:
  partition_expr, partition_expr [, partition_expr, ...]
  
partition_expr:
    partition_column	
  | partition_func(partition_column)


# 分区函数定义
partition_func:
    RIGHT
  | LEFT
  | SUBSTR
  | SUBSTRING
说明

CO_HASH分区策略与HASH/KEY分区策略的主要区别请参见与Hash/Key分区策略的主要区别

限制

  • 分区列使用分区函数时,不允许嵌套多层的分区函数,例如SUBSTR(SUBSTR(c1,-6),4)

  • 所有分区列的类型必须完全一致,包括:

    • 分区列类型的charset与collation;

    • 分区列类型的长度定义或精度定义等。

  • 默认最大分区数目不允许超过8192。

  • 默认最大分区列数目不允许超过5个。

  • 分区函数的使用限制:

    • RIGHT

    • LEFT

    • SUBSTR

示例

假如业务有一张订单表orders,它的每一行录的order_id与buyer_id的后6位的数字总是相同的。

那么,如果用户想对订单表orders同时按order_id与buyer_id两个列的后6位数字进行分区,并期望同一行order_id与buyer_id这两个列的等值查询条件均能路由到同一个分区的话,可以使用如下的语法定义:

CREATE TABLE t_orders(
 id bigint not null auto_increment, 
 seller_id bigint,
 order_id bigint, 
 buyer_id bigint,
 order_time datetime not null,
 primary key(id)
) 
PARTITION BY CO_HASH(
  	RIGHT(`order_id`,6) /*取c1列的后6位字符*/,
  	RIGHT(`buyer_id`,6) /*取c2列的后6位字符*/
)  
PARTITIONS 8;

CO_HASH与其它分区函数的用法,请参见分区函数

相关限制

数据类型限制

  • 整数类型: BIGINT/BIGINT UNSINGEDINT/INT/INT UNSINGED/MEDIUMINT/MEDIUMINT UNSINGED/SMALLINT/SMALLINT UNSINGED/TINYINT/TINYINT UNSINGED

  • 时间类型:DATETIME/DATE/TIMESTAMP

  • 字符串类型:CHAR/VARCHR

  • 定点类型:DECIMAL(小数部分的位数要求必须是0)

分区列相关限制

  • 分区列取值的协同关系必须由业务保证,分区表仅校验路由结果。CO_HASH由于多个分区列之间的取值存在着由业务维护的协同的关系。因此,对于CO_HASH分区表的每一行记录的插入,不同分区列的值的分区路由结果要求必须是一致的。但是,即使同一行的记录不同的分区列的取值的分区路由结果完全一致,也不一定能保证这些分区列的协同关系不被破坏。因此,分区列之间的协同关系必须由用户自行保证,PolarDB-X只负责检验路由结果,不负责校验数据本身的协同关系,例如:业务定义c1与c2的后4位字符是相同的,现在假如c1=1001234与c2=1320都能路由分片0,那么inssert (c1,c2) values (100234,1320)是允许的,但此时c1与c2的后4位并不相同。

  • DML修改分区列限制。由于CO_HASH的多个分区列之间的取值存在协同的关系,为防止数据分布错误,PolarDB-X对于DML关于CO_HASH分区列的值的修改。

    • 对于INSERT/REPLCAE语句,VALUES子句中同一行的不同分区列的值在路由计算后,其分区结果若不一致,将被禁止插入并报错;

    • 对于UPDATE及UPSERT语句,SET子句在修改分区列的取值时,必须要对所有分区列同时进行修改,比如,c1与c2是分区列,那么应该是UPDATE t1 SET c1='xx',c2='yy' WHERE id=1 。如果SET子句在修改分区列后的值,并且会导致同一行的不同分区列的取值产生不同的分区路由结果的话,该UPDATE语句或UPSERT语句将被禁止并报错;

    • 如果使用了CO_HASH作为GSI的分区策略,那么所有对主表的INSERT/UPDATE等操作,若该DML操作会导致主表的GSI表的同一行数据的不同分区列的取值产生不同的分区路由结果,那么,该DML操作也将被禁止并报错。

  • 关于整数类型前缀0的说明。CO_HASH的分区列之间的协同关系,所以它的分区列通常需要借助使用SUBSTR/LEFT/RIGHT等分区函数进行定义。因此,一些整数类型的数字被截取后,容易出现前缀为0的情况。比如,业务定义 c1 与 c2 的后4位字符是相同的,现在假如 c1=1000034 与 c2=34, c1的后4位字符是’0034‘。CO_HASH对于类型是整数类型的分区列,所有原始的数字被截取后,都会统一自动转为分区列对应的整数类型再进行路由。因此,对于'0034' 的字符串,它实际会被转为整数34 再进行哈希值计算并路由分区,从而自动处理前缀0。