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 id
和order id
前5位一定一致(或者算出来的hash value mod
)一致?
如果你是业务开发者, 难道要遵循数据库对业务强加的这种限制?
1、两个拆分键皆不能修改。
可以修改, 但是需要实现跨库事务, 因为修改分区键后, 这条新记录可能应该迁移到其他DN.
2、键值可以不一样, 但是可以保留原来的限制. 例如通过另一个参数来指定是否允许修改. 这样在限制情况下优化器依旧能使用之前的优化策略.
sell_id=?
肯定可以路由到某个DN.
order_id=?
路由到所有DN, 然后汇总.
更多字段以此类推.