Apache Doris数据分区Partition、数据分桶(distributed by)

目录

  • 1. 数据分区和分桶的关系
  • 2. 数据分区
    • 2.1 range分区
      • 2.1.1 多列range分区
    • 2.2 list分区
      • 2.2.1 多列list分区
  • 3. 数据分桶
  • 4. 关于Partition和Bucket的数量和数据量的建议
  • 5. 建表语句properties设置
    • 5.1 replication_num
    • 5.2 storage_medium & storage_cooldown_time
  • 6. ENGINE

1. 数据分区和分桶的关系

  • 先分区,再分桶。一个表不指定分区,默认只有一个分区
  • 一个Partition有多个数据分片Tablet。Tablet数据移动、复制操作的最小物理存储单元。Partition是数据的导入与删除的最小管理单位
  • 一个表的Tablet总数量等于(Partition num * Bucket num)
  • 分区支持Range和List分区;分桶只支持Hash分桶

2. 数据分区

  • 分区列必须为key列
  • 不论什么字段数据类型,建表时写分区值,都必须加引号
  • 通过SQLadd partition添加分区,可以为该分区单独指定Bucket数量

2.1 range分区

mysql> 
mysql> create table if not exists test_db.range_tb(
    -> user_id largeint not null comment '用户id',
    -> date date not null comment '数据插入日期',
    -> timestamp datetime not null comment '数据插入时间戳',
    -> city varchar(20) comment '城市',
    -> age smallint comment '年龄',
    -> sex tinyint comment '性别',
    -> last_visit_date datetime replace default '1970-01-01 00:00:00' comment '用户最后一次访问时间',
    -> cost bigint sum default '0' comment '用户总消费',
    -> max_dwell_time int max default '0' comment '用户最大停留时间',
    -> min_dwell_time int min default '0' comment '用户最小停留时间'
    -> )
    -> engine = olap
    -> aggregate key(user_id, date, timestamp, city, age, sex)
    -> partition by range(date)
    -> (
    -> partition p202107 values less than ('2017-08-01'),
    -> partition p202108 values less than ('2017-09-01'),
    -> partition p202109 values less than ('2017-10-01')
    -> )
    -> distributed by hash(user_id) buckets 10
    -> properties
    -> (
    -> 'replication_num' = '3',
    -> 'storage_medium'='SSD',
    -> 'storage_cooldown_time'='2022-01-01 00:00:00'
    -> );
Query OK, 0 rows affected (0.30 sec)

mysql> 
  • 分区列通常为时间列,以方便管理新旧数据
  • 也可以通过values [(‘xxx’), (‘xxx’))同时指定上下界
  • 分区的删除不会改变已存在分区的范围。删除分区可能出现空洞。无法往不存在的分区insert数据
  • 通过values less than语句增加分区时,分区的下界紧接上一个分区的上界

2.1.1 多列range分区

mysql> 
mysql> create table if not exists test_db.multi_range_tb(
    -> user_id largeint not null comment '用户id',
    -> date date not null comment '数据插入日期',
    -> timestamp datetime not null comment '数据插入时间戳',
    -> city varchar(20) comment '城市',
    -> age smallint comment '年龄',
    -> sex tinyint comment '性别',
    -> last_visit_date datetime replace default '1970-01-01 00:00:00' comment '用户最后一次访问时间',
    -> cost bigint sum default '0' comment '用户总消费',
    -> max_dwell_time int max default '0' comment '用户最大停留时间',
    -> min_dwell_time int min default '0' comment '用户最小停留时间'
    -> )
    -> engine = olap
    -> aggregate key(user_id, date, timestamp, city, age, sex)
    -> partition by range(date, user_id)
    -> (
    -> partition p202107_1000 values less than ('2021-08-01', '1000'),
    -> partition p202108_2000 values less than ('2021-09-01', '2000'),
    -> partition p202109_all values less than ('2021-10-01')
    -> ) 
    -> distributed by hash(user_id) buckets 10
    -> properties
    -> (
    -> 'replication_num' = '3',
    -> 'storage_medium'='SSD',
    -> 'storage_cooldown_time'='2022-01-01 00:00:00'
    -> );
Query OK, 0 rows affected (0.07 sec)

mysql> 

分区结果为:

p202107_1000:    [(MIN_VALUE,  MIN_VALUE), ("2021-08-01", "1000")   )
p202108_2000:    [("2021-08-01", "1000"),  ("2021-09-01", "2000")   )
p202109_all:     [("2021-09-01", "2000"),  ("2021-10-01", MIN_VALUE)) 

插入数据落入分区的情况如下:

数据                -->   分区
2021-07-01, 200     -->   p202107_1000
2021-07-01, 2000    -->   p202107_1000
2021-08-01, 100     -->   p202107_1000
2021-08-01, 2000    -->   p202108_2000
2021-08-15, 5000    -->   p202108_2000
2021-09-01, 2000    -->   p202109_all
2021-09-10, 1       -->   p202109_all
2021-10-01, 1000    -->   无法导入
2021-11-01, 1000    -->   无法导入
  • 前面的分区列优先级高。但如果前面的分区列介于分区的临界点,以后面的分区列为准,如(2021-08-01, 100)、(2021-08-01, 999)都会落入p202107_1000

2.2 list分区

0.14.0版本还未支持,只是看了最新master版本的文档,做了以下记录,并未实操

create table if not exists test_db.list_tb(
user_id largeint not null comment '用户id',
date date not null comment '数据插入日期',
timestamp datetime not null comment '数据插入时间戳',
city varchar(20) comment '城市',
age smallint comment '年龄',
sex tinyint comment '性别',
last_visit_date datetime replace default '1970-01-01 00:00:00' comment '用户最后一次访问时间',
cost bigint sum default '0' comment '用户总消费',
max_dwell_time int max default '0' comment '用户最大停留时间',
min_dwell_time int min default '0' comment '用户最小停留时间'
)
engine = olap
aggregate key(user_id, date, timestamp, city, age, sex)
partition by list(city)
(
partition p_cn values in ('Beijing', 'Shanghai', 'Hong Kong'),
partition p_usa values in ('New York', 'San Francisco'),
partition p_jp values in ('Tokyo')
)
distributed by hash(user_id) buckets 10
properties
(
'replication_num' = '3',
'storage_medium'='SSD',
'storage_cooldown_time'='2022-01-01 00:00:00'
);
  • 分区列支持boolean、tinyint、smallint、int、bigint、largeint、date、datetime、char、varchar数据类型
  • 不可添加范围重叠的分区

2.2.1 多列list分区

create table if not exists test_db.list_tb(
user_id largeint not null comment '用户id',
date date not null comment '数据插入日期',
timestamp datetime not null comment '数据插入时间戳',
city varchar(20) comment '城市',
age smallint comment '年龄',
sex tinyint comment '性别',
last_visit_date datetime replace default '1970-01-01 00:00:00' comment '用户最后一次访问时间',
cost bigint sum default '0' comment '用户总消费',
max_dwell_time int max default '0' comment '用户最大停留时间',
min_dwell_time int min default '0' comment '用户最小停留时间'
)
engine = olap
aggregate key(user_id, date, timestamp, city, age, sex)
partition by list(user_id, city)
(
partition p1_city values in (('1', 'Beijing'), ('1', 'Shanghai')),
partition p2_city values in (('2', 'Beijing'), ('2', 'Shanghai')),
partition p3_city values in (('3', 'Beijing'), ('3', 'Shanghai'))
)
distributed by hash(user_id) buckets 10
properties
(
'replication_num' = '3',
'storage_medium'='SSD',
'storage_cooldown_time'='2022-01-01 00:00:00'
);

分区结果为:

p1_city: [("1", "Beijing"), ("1", "Shanghai")]
p2_city: [("2", "Beijing"), ("2", "Shanghai")]
p3_city: [("3", "Beijing"), ("3", "Shanghai")]

插入数据落入分区的情况如下:

数据           --->   分区
1, Beijing     --->   p1_city
1, Shanghai    --->   p1_city
2, Shanghai    --->   p2_city
3, Beijing     --->   p3_city
1, Tianjin     --->   无法导入
4, Beijing     --->   无法导入

3. 数据分桶

  • 分桶列必须为key列,可以为多列
  • 一个Partition的Bucket数量一旦指定,不可更改。不同Partition的Bucket数量可以不一样
  • 分桶列多适用于低并发高吞吐量,因为数据分布在多个桶中,并发查询多个桶,单个查询速度快
  • 分桶列少适用于高并发,因为一个查询可能只命中一个桶,多个查询之间查询不同的桶,磁盘的IO影响小,所以并发就高

4. 关于Partition和Bucket的数量和数据量的建议

  • 一个表的Tablet数量,推荐略多于整个集群的磁盘数量
  • 单个Tablet的数据量建议在 1G - 10G 的范围内。如果单个Tablet数据量过小,则数据的聚合效果不佳,且元数据管理压力大。如果数据量过大,则不利于副本的迁移、同步,且会增加Schema Change或者Rollup操作失败重试的代价(这些操作失败重试的粒度是Tablet)
  • 当Tablet数量和数据量冲突时,数据量优先。比如一个很小的集群,表的数据量很大,则需要很多Tablet(远多于集群的磁盘数量)
  • 表的数据量可以通过show data命令查看,结果除以副本数,即表的数据量

5. 建表语句properties设置

5.1 replication_num

  • Tablet副本数量默认为3。在增加新分区时,可以单独指定新分区中Tablet的副本数量,alter table multi_range_tb add partition p202110_3000 values less than ('2021-11-01', '3000') ('replication_num' = '1');
  • 副本数量可以在运行时修改。强烈建议保持奇数
  • 最大副本数取决于物理机的ip数量,而不是BE数量。如一台物理机有2个ip,部署了3个BE,则最大副本数只能是2
  • 对于数量小且更新不频繁的维度表,可以设置更多replication_num,提升本地join的概率

5.2 storage_medium & storage_cooldown_time

  • 可以通过fe.conf中的default_storage_medium=xxx进行修改,默认为HDD
  • 当storage_medium指定为HDD时,不能指定storage_cooldown_time参数
  • 当storage_medium指定为SSD时,如果SSD介质不存在、不可访问、空间不足,默认会储存到可用的HDD介质上;当FE参数enable_strict_storage_medium_check为True,会直接报错
  • 当storage_medium指定为SSD时,默认30天后会从SSD迁移到HDD,否则按storage_cooldown_time指定的时间进行迁移

6. ENGINE

默认的表ENGINE是olap,由Doris负责管理。其它表引擎如mysql、es等,Doris只负责元数据映射,不储存数据,以便进行数据读取

你可能感兴趣的:(#,Apache,Doris,doris,数据分区,partition,by,数据分桶,distributed,by)