方案背景——为什么要进行分区?

一是老板通Tidb集群每天涉及50+张表、2亿多条数据回流,合理使用Hash可以把写入压力打散到不同的TiKV;

二是对于大集团数据做聚合,利用分区裁剪原理,查询时可以充当前置索引,预先过滤出部分数据,加速查询效率。

分区方案

由于TiDB不支持对多列进行分区(例如:group_id + report_date),因此我们目前的解决办法是将 需要分区的字段组合成一个值,由数仓计算出,放在 partition_id 这个字段中,建表时通过partition_id分区。

通过不断探索,目前得到相对最优的公式:partition_id = (group_id * 100000000 + report_date) % 29

为什么要对29取余?

因为group_id本身不离散,因此需要把它离散掉。通过测试,发现如果对质数(素数)取余相对比较离散,而如果对非素数(10,20,128…)取余离散性较差。

参考如下:

图1是对10取余进行分区,数据回流时tidb kv999,可以看到存在热点kv,数据不离散。

图2是对29进行取余分区,数据回流时tidb kv999,可以看到无热点kv,相对均衡。

tidb_mem_quota_query 默认_数据库


tidb_mem_quota_query 默认_分区_02

分区与不分区查询测试对比

总得来说,随着查询记录数的增多,分区表比不分区表查询效率高出30%。

tidb_mem_quota_query 默认_分区_03

分区方式选择

Hash分区

最开始我们也是采用的Hash分区,确实能够将数据离散到不同分区,但是查询效率并没有明显提升。

主要原因是: Hash分区不支持范围查询,例如我们常用的( where report_date between 20220101 and 20220102) 这种方式依然会扫描所有的分区。

因此,果断放弃Hash分区方式,转而研究Range分区,因为Range分区支持范围查询。

Range分区

Range分区需要提前建好分区,因此我们建了29个分区,将数据根据partition_id离散到了29个不同的分区。

以宽表为例,预先回流两个表(30天数据,每天100w左右),一个按range分29个区,一个不分区。

demo

CREATE TABLE `xxxx` (
 ......
  `partition_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '分区key((groupID * 100000000 + report_date)% 29),例如:1234520220606%29 =15 ',
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin/*!90000 SHARD_ROW_ID_BITS=4 */
PARTITION BY RANGE ( `partition_id` ) (
  PARTITION `p1` VALUES LESS THAN (1),
  PARTITION `p2` VALUES LESS THAN (2),
  PARTITION `p3` VALUES LESS THAN (3),
  PARTITION `p4` VALUES LESS THAN (4),
  PARTITION `p5` VALUES LESS THAN (5),
  PARTITION `p6` VALUES LESS THAN (6),
  PARTITION `p7` VALUES LESS THAN (7),
  PARTITION `p8` VALUES LESS THAN (8),
  PARTITION `p9` VALUES LESS THAN (9),
  PARTITION `p10` VALUES LESS THAN (10),
  PARTITION `p11` VALUES LESS THAN (11),
  PARTITION `p12` VALUES LESS THAN (12),
  PARTITION `p13` VALUES LESS THAN (13),
  PARTITION `p14` VALUES LESS THAN (14),
  PARTITION `p15` VALUES LESS THAN (15),
  PARTITION `p16` VALUES LESS THAN (16),
  PARTITION `p17` VALUES LESS THAN (17),
  PARTITION `p18` VALUES LESS THAN (18),
  PARTITION `p19` VALUES LESS THAN (19),
  PARTITION `p20` VALUES LESS THAN (20),
  PARTITION `p21` VALUES LESS THAN (21),
  PARTITION `p22` VALUES LESS THAN (22),
  PARTITION `p23` VALUES LESS THAN (23),
  PARTITION `p24` VALUES LESS THAN (24),
  PARTITION `p25` VALUES LESS THAN (25),
  PARTITION `p26` VALUES LESS THAN (26),
  PARTITION `p27` VALUES LESS THAN (27),
  PARTITION `p28` VALUES LESS THAN (28),
  PARTITION `p29` VALUES LESS THAN (MAXVALUE)
)