Skip to content

Latest commit

 

History

History
122 lines (63 loc) · 5.05 KB

20230209_03.md

File metadata and controls

122 lines (63 loc) · 5.05 KB

PolarDB-X range_hash 分库分表例子 - 以及设计边界的分析例子

作者

digoal

日期

2023-02-09

标签

PostgreSQL , PolarDB , 分库分表 , range_hash


背景

https://www.polardbx.com/document

使用双字段哈希函数做拆分

使用要求拆分键的类型必须是字符类型或数字类型。

路由方式根据任一拆分键后N位计算哈希值,以哈希方式完成路由计算。N为函数第三个参数。例如RANGE_HASH(COL1, COL2, N),计算时会优先选择COL1,截取其后N位进行计算。COL1不存在时按COL2计算。

适用场景适合于需要有两个拆分键,并且仅使用其中一个拆分键值进行查询时的场景。假设用户的里已经分了8个物理库, 现业务有如下的场景:

一个业务想按买家ID和订单ID对订单表进行分库。

查询时条件仅有买家ID或订单ID。

此时可使用以下DDL对订单表进行构建:

create table test_order_tb (  
 id bigint not null auto_increment,  
 seller_id varchar(30) DEFAULT NULL,  
 order_id varchar(30) DEFAULT NULL,  
 buyer_id varchar(30) DEFAULT NULL,  
 create_time datetime DEFAULT NULL,  
 primary key(id)  
) ENGINE=InnoDB DEFAULT CHARSET=utf8   
dbpartition by RANGE_HASH(buyer_id, order_id, 10)   
tbpartition by RANGE_HASH(buyer_id, order_id, 10)   
tbpartitions 3;   

说明

两个拆分键皆不能修改。

插入数据时如果发现两个拆分键指向不同的分库或分表时,插入会失败。

对说明部分的两条限制的设计分析

为什么要加这两条限制:

range_hash(sell_id, order_id, 5)为例解释.

1、两个拆分键皆不能修改。

因为分库分表的字段值一旦被修改后, 按照range_hash(新值)重算, 这条新的数据可能不属于当前分片表, 那么就会涉及到行迁移, 可能迁移到DN内的其他分片, 也可能要迁移到其他DN的其他分片. 跨库还会涉及到分布式事务.

猜测应该是当前polardb-x版本暂时还不支持, 所以先限制这个操作.

2、插入数据时如果发现两个拆分键指向不同的分库或分表时,插入会失败。

和上一个限制一样, 如果两个拆分键指向不同的分库或分表时, 路由逻辑会变得更复杂.

sell_id=? 肯定可以路由到某个DN.

order_id=? , 按range_hash的逻辑, sell_id不为空时按sell_id来计算分片位置, 所以这样的tuple 使用order_id值无法决定放哪个分片, 按order_id=?来查询, 也就只能路由到所有DN, 然后汇总.

因此polardb-x当前的版本, 做了这个限制, 要求所有range_hash里面的键值都必须指向同一分片. 不管用户查sell_id=? 还是 order_id=? , 都可以算出应该路由到哪个分片. 因为他们已经被限制了必需出现在同一分片.

但是, 这样就会和业务出现冲突:

例如range_hash(sell_id, order_id, 5);

怎么保证sell idorder id前5位一定一致(或者算出来的hash value mod)一致?

如果你是业务开发者, 难道要遵循数据库对业务强加的这种限制?

建议的改进策略

1、两个拆分键皆不能修改。

可以修改, 但是需要实现跨库事务, 因为修改分区键后, 这条新记录可能应该迁移到其他DN.

2、键值可以不一样, 但是可以保留原来的限制. 例如通过另一个参数来指定是否允许修改. 这样在限制情况下优化器依旧能使用之前的优化策略.

sell_id=? 肯定可以路由到某个DN.

order_id=? 路由到所有DN, 然后汇总.

更多字段以此类推.

digoal's wechat