暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

AntDB 数据库分布式功能-表分布2

tocata 2024-09-02
51

指定分布方式

AntDB 支持四种分布方式:

  • hash(列名):哈希分布,根据列的值做哈希计算,来决定当前 tuple 分布到哪个节点上,默认的分布方式;
  • replicaiton:复制分布,每一个节点都存一个副本;
  • modulo:取模分布;
  • random:随机分布,随机分布到某一个节点上;

用户可以在建表语句 CREATE TABLE 中使用 DISTRIBUTE BY 关键字来指定分片方式。除复制表外,其他三种数据分片方式都是基于键的分片。比如 Hash 分片的原理是使用新写入数据的某个键值 —— 比如客户 ID、客户端 IP、ZIP 码等等 —— 通过哈希函数决定保存的数据节点(也就是分片位置)。

哈希分布

哈希分布是指对分片键的数据计算hash值,根据计算出的 hash 值来决定数据分布到哪个存储节点,即 datanode 节点。对于哈希表,要选取一个分片键。一张分布式表只能有一个分片键,分片键是用于划分和定位表的列,不能修改,默认的分布列是第一列。

以下两种写法是等效的:

CREATE TABLE t1(id int, num int, des text) DISTRIBUTE BY hash(id);
CREATE TABLE t1(id int, num int, des text) ;

如果某一列上有 primary key 或者 unique 约束,则会把唯一列默认作为分片键。如下,在 num 列上有主键约束,则默认会发 num 列作为分片键。

CREATE TABLE t1(id int, num int primary key, des text);
\d+ t1
antdb=# \d+ t1
                                     Table "public.t1"
 Column |  Type   | Collation | Nullable | Default | Storage  | Stats target | Description 
--------+---------+-----------+----------+---------+----------+--------------+-------------
 id     | integer |           |          |         | plain    |              | 
 num    | integer |           | not null |         | plain    |              | 
 des    | text    |           |          |         | extended |              | 
Indexes:
    "t1_pkey" PRIMARY KEY, btree (num)
DISTRIBUTE BY HASH(num) TO NODE(dm1, dm2, dm3, dm4, dm5, dm6)
Access method: heap

以下两种写法等效:

CREATE TABLE t1(id int, num int primary key, des text);
CREATE TABLE t1(id int, num int , des text) DISTRIBUTE BY hash(num);

注意: 在 AntDB 分布式版本上,分片列和唯一列必须为同一列,否则报错:

antdb=# CREATE TABLE t1(id int unique, num int , des text) DISTRIBUTE BY hash(num);
ERROR:  Distribution column is not in index column list, create index cannot be supported

合理选择分片键

一个表中有很多列,选择哪一列作为分片键呢?合理选择分片键能够提高查询效率。选择分片键的时候,要注意一下几个问题。

  • 分片字段尽量和 join 连接字段保持一致

    只要是进行切分,跨节点 join 的问题是不可避免的。但是良好的设计和切分可以减少此类情况的发生。解决这一问题,要求分片字段和 join 连接字段保持一致,当查询可以下推至节点运算时,可以有效解决此类问题。如果运算不允许下推至节点,可以将数据量较小的表修改为复制表后(数据量不超过 1000 万),也能实现本节点运算的能力。

  • 分片字段尽量和聚合字段保持一致

    跨节点 order by,group by,count 等聚合函数问题是一类问题,因为它们都需要基于全部数据集合进行计算。解决这一问题,要求分片字段和聚合字段保持一致,当聚合可以下推至节点运算时,可以有效解决此类问题。

  • 分片键选择时,尽量保证数据能够均匀分布。

  • 分片键选择时,尽量保证事务控制在分片范围内(本节点),避免出现跨分片(跨节点)。

复制分布

复制分布则会在每一个 datanode 上都保留一份数据的副本,这会造成数据冗余,仅适用于使用频率非常高的小表。例如,全国所有的省份信息表,这样的表本身数据量有限,但是会经常与其它大表进行 join 操作,创建为复制表不会占用较多空间,确能提高查询效率。

示例,创建一个复制表,插入一些数据。

CREATE TABLE t1(id int, num int, des text) DISTRIBUTE BY replication;
INSERT INTO t1 VALUES(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8);

可以看到,在每一个 datanode 上都有全部的数据。

antdb=# EXECUTE DIRECT ON  (dn1) 'SELECT * FROM  t1';
 id | num | des 
----+-----+-----
  1 |   1 | 
  2 |   2 | 
  3 |   3 | 
  4 |   4 | 
  5 |   5 | 
  6 |   6 | 
  7 |   7 | 
  8 |   8 | 
(8 rows)

antdb=# EXECUTE DIRECT ON  (dn2) 'SELECT * FROM  t1';
 id | num | des 
----+-----+-----
  1 |   1 | 
  2 |   2 | 
  3 |   3 | 
  4 |   4 | 
  5 |   5 | 
  6 |   6 | 
  7 |   7 | 
  8 |   8 | 
(8 rows)

取模分布

取模分布与哈希分布类似,只是内部计算方式不同,类似于除以节点数取余数来决定分布的节点。

示例,创建表 t1 分布方式是取模分布,分布节点是 dn1 和 dn2。

CREATE TABLE t1(id int, num int, des text) DISTRIBUTE BY modulo(id) to node(dn1, dn2, dn3);
INSERT INTO t1 VALUES(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8);

查看表在 dn1、dn2 和 dn3 上数据分布如下:

antdb=# EXECUTE DIRECT ON  (dn1) 'SELECT * FROM  t1';
 id | num | des 
----+-----+-----
  3 |   3 | 
  6 |   6 | 
(2 rows)

antdb=# EXECUTE DIRECT ON  (dn2) 'SELECT * FROM  t1';
 id | num | des 
----+-----+-----
  1 |   1 | 
  4 |   4 | 
  7 |   7 | 
(3 rows)

antdb=# EXECUTE DIRECT ON  (dn3) 'SELECT * FROM  t1';
 id | num | des 
----+-----+-----
  2 |   2 | 
  5 |   5 | 
  8 |   8 | 
(3 rows)

随机分布

随机分布,顾名思义,是指将数据随机分布在某一个 datanode 上。此种分布方式的优点是数据会非常均匀分布在所有的节点上。前面介绍的哈希分布和取模分布都有可能造成数据倾斜(即根据计算得出,某一个 datanode 上存放的数据很多,而其它 datanode 上的数据较少的情况),复制分布又会造成空间浪费,只有随机分布能解决此问题。

由于数据完全随机分布,没有一个固定的算法来决定数据分布在哪个节点上,所以当查询数据时,无法根据某一列的值来定位到某一个 datanode,因此需要在所有的 datanode 上,查找数据,从而造成查询效率的低下。

示例,第一次创建表 t1,查看 dn1 节点上存放的数据如下:

CREATE TABLE t1(id int, num int, des text) DISTRIBUTE BY random to node(dn1, dn2, dn3);
INSERT INTO t1 VALUES(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8);
EXECUTE DIRECT ON  (dn1) 'SELECT * FROM  t1';
antdb=#  EXECUTE DIRECT ON  (dn1) 'SELECT * FROM  t1';
 id | num | des 
----+-----+-----
  2 |   2 | 
  5 |   5 | 
  6 |   6 | 
  7 |   7 | 
(4 rows)

删掉表 t1,再次创建表 t1,插入同样的数据,查看 dn1 节点上存放的数据,发现数据分布与第一次不同,因为每次插入数据都是随机的,所以两次随机分布的结果不同:

DROP TABLE t1;
CREATE TABLE t1(id int, num int, des text) DISTRIBUTE BY random to node(dn1, dn2, dn3);
INSERT INTO t1 VALUES(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8);
EXECUTE DIRECT ON  (dm1) 'SELECT * FROM  t1';

antdb=#  EXECUTE DIRECT ON  (dn1) 'SELECT * FROM  t1';
 id | num | des 
----+-----+-----
  7 |   7 | 
(1 row)
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论