Doris分区与分桶(八)

接上篇----------Doris 建表示例

Doris 支持两层的数据划分。第一层是 Partition,支持 Range 和 List 的划分方式。第二层是 Bucket(Tablet),仅支持 Hash 的划分方式。

也可以仅使用一层分区。使用一层分区时,只支持 Bucket 划分。

Partition
  • Partition 列可以指定一列或多列。分区类必须为 KEY 列。

  • 不论分区列是什么类型,在写分区值时,都需要加双引号。

  • 分区数量理论上没有上限。

  • 当不使用 Partition 建表时,系统会自动生成一个和表名同名的,全值范围的Partition。该 Partition 对用户不可见,并且不可删改。

Range 分区

分区列通常为时间列,以方便的管理新旧数据。不可添加范围重叠的分区。 Partition 指定范围的方式

VALUES LESS THAN (...) 仅指定上界,系统会将前一个分区的上界作为该分区的下界,生成一个左闭右开的区间。分区的删除不会改变已存在分区的范围。删除分区可能出现空洞。

VALUES [...) 指定同时指定上下界,生成一个左闭右开的区间。

通过 VALUES [...) 同时指定上下界比较容易理解。这里举例说明,当使用 VALUES LESS THAN (...) 语句进行分区的增删操作时,分区范围的变化情况:

(1)如上 expamle_range_tbl 示例,当建表完成后,会自动生成如下 3 个分区:

复制代码
p201701: [MIN_VALUE, 2017-02-01)
p201702: [2017-02-01, 2017-03-01)
p201703: [2017-03-01, 2017-04-01)

(2)增加一个分区 p201705 VALUES LESS THAN ("2017-06-01"),分区结果如下:

复制代码
p201701: [MIN_VALUE, 2017-02-01)
p201702: [2017-02-01, 2017-03-01)
p201703: [2017-03-01, 2017-04-01)
p201705: [2017-04-01, 2017-06-01)

(3)此时删除分区 p201703,则分区结果如下:

复制代码
p201701: [MIN_VALUE, 2017-02-01)
p201702: [2017-02-01, 2017-03-01)
p201705: [2017-04-01, 2017-06-01)

注意到 p201702 和 p201705 的分区范围并没有发生变化,而这两个分区之间,出现了一个空洞:[2017-03-01, 2017-04-01)。即如果导入的数据范围在这个空洞范围内,是无法导入的。

(4)继续删除分区 p201702,分区结果如下:

复制代码
p201701: [MIN_VALUE, 2017-02-01)
p201705: [2017-04-01, 2017-06-01)

空洞范围变为:[2017-02-01, 2017-04-01)

(5)现在增加一个分区 p201702new VALUES LESS THAN ("2017-03-01"),分区结果如下:

复制代码
p201701: [MIN_VALUE, 2017-02-01)
p201702new: [2017-02-01, 2017-03-01)
p201705: [2017-04-01, 2017-06-01)

可以看到空洞范围缩小为:[2017-03-01, 2017-04-01)

(6)现在删除分区 p201701,并添加分区 p201612 VALUES LESS THAN ("2017-01-01"),分区结果如下:

复制代码
p201612: [MIN_VALUE, 2017-01-01)
p201702new: [2017-02-01, 2017-03-01)
p201705: [2017-04-01, 2017-06-01)

即出现了一个新的空洞:[2017-01-01, 2017-02-01)

List 分区

分 区 列支 持 BOOLEAN, TINYINT, SMALLINT, INT, BIGINT, LARGEINT, DATE, DATETIME, CHAR, VARCHAR 数据类型,分区值为枚举值。只有当数据为目标分区枚举值

其中之一时,才可以命中分区。不可添加范围重叠的分区。

Partition 支持通过 VALUES IN (...) 来指定每个分区包含的枚举值。下面通过示例说明,进行分区的增删操作时,分区的变化。

(1)如上 example_list_tbl 示例,当建表完成后,会自动生成如下 3 个分区:

复制代码
p_cn: ("Beijing", "Shanghai", "Hong Kong")
p_usa: ("New York", "San Francisco")
p_jp: ("Tokyo")

(2)增加一个分区 p_uk VALUES IN ("London"),分区结果如下:

复制代码
p_cn: ("Beijing", "Shanghai", "Hong Kong")
p_usa: ("New York", "San Francisco")
p_jp: ("Tokyo")
p_uk: ("London")

(3)删除分区 p_jp,分区结果如下:

复制代码
p_cn: ("Beijing", "Shanghai", "Hong Kong")
p_usa: ("New York", "San Francisco")
p_uk: ("London")

Bucket

(1)如果使用了 Partition,则 DISTRIBUTED ... 语句描述的是数据在各个分区内的划分规则。如果不使用 Partition,则描述的是对整个表的数据的划分规则。

(2)分桶列可以是多列,但必须为 Key 列。分桶列可以和 Partition 列相同或不同。

(3)分桶列的选择,是在 查询吞吐 和 查询并发 之间的一种权衡:

  • ① 如果选择多个分桶列,则数据分布更均匀。如果一个查询条件不包含所有分桶列的等值条件,那么该查询会触发所有分桶同时扫描,这样查询的吞吐会增加,单个查询的延迟随之降低。这个方式适合大吞吐低并发的查询场景。

  • ② 如果仅选择一个或少数分桶列,则对应的点查询可以仅触发一个分桶扫描。此时,当多个点查询并发时,这些查询有较大的概率分别触发不同的分桶扫描,各个查询之间的 IO 影响较小(尤其当不同桶分布在不同磁盘上时),所以这种方式适合高并发的点查询场景。

(4)分桶的数量理论上没有上限。

使用复合分区的场景

以下场景推荐使用复合分区

(1)有时间维度或类似带有有序值的维度,可以以这类维度列作为分区列。分区粒度可以根据导入频次、分区数据量等进行评估。

(2)历史数据删除需求:如有删除历史数据的需求(比如仅保留最近 N 天的数据)。使用复合分区,可以通过删除历史分区来达到目的。也可以通过在指定分区内发送 DELETE 语句进行数据删除。

(3)解决数据倾斜问题:每个分区可以单独指定分桶数量。如按天分区,当每天的数据量差异很大时,可以通过指定分区的分桶数,合理划分不同分区的数据,分桶列建议选择区分度大的列。

多列分区

Doris 支持指定多列作为分区列,示例如下:

1)Range 分区
复制代码
PARTITION BY RANGE(`date`, `id`)
(
 PARTITION `p201701_1000` VALUES LESS THAN ("2017-02-01", "1000"),
 PARTITION `p201702_2000` VALUES LESS THAN ("2017-03-01", "2000"),
 PARTITION `p201703_all` VALUES LESS THAN ("2017-04-01")
)

指定 date(DATE 类型) 和 id(INT 类型) 作为分区列。以上示例最终得到的分区如下:

复制代码
p201701_1000: [(MIN_VALUE, MIN_VALUE), ("2017-02-01", "1000") )
p201702_2000: [("2017-02-01", "1000"), ("2017-03-01", "2000") )
p201703_all: [("2017-03-01", "2000"), ("2017-04-01", MIN_VALUE))

注意,最后一个分区用户缺省只指定了 date 列的分区值,所以 id 列的分区值会默认填充 MIN_VALUE。当用户插入数据时,分区列值会按照顺序依次比较,最终得到对应的分区。举例如下:

复制代码
数据 --> 分区
2017-01-01, 200 --> p201701_1000
2017-01-01, 2000 --> p201701_1000
2017-02-01, 100 --> p201701_1000
2017-02-01, 2000 --> p201702_2000
2017-02-15, 5000 --> p201702_2000
2017-03-01, 2000 --> p201703_all
2017-03-10, 1 --> p201703_all
2017-04-01, 1000 --> 无法导入
2017-05-01, 1000 --> 无法导入
2)List 分区
复制代码
PARTITION BY LIST(`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"))
)

指定 id(INT 类型) 和 city(VARCHAR 类型) 作为分区列。最终得到的分区如下:

复制代码
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 ---> 无法导入

接下篇----------Doris的PROPERTIES与ENGINE

相关推荐
zhangjin12221 小时前
kettle从入门到精通 第九十四课 ETL之kettle MySQL Bulk Loader大批量高性能数据写入
大数据·数据仓库·mysql·etl·kettle实战·kettlel批量插入·kettle mysql
宅小海15 小时前
14 配置Hadoop集群-配置历史和日志服务
linux·服务器·hadoop
珹洺17 小时前
Java-servlet(十)使用过滤器,请求调度程序和Servlet线程(附带图谱表格更好对比理解)
java·开发语言·前端·hive·hadoop·servlet·html
2401_8712905821 小时前
Hadoop 集群的常用命令
大数据·hadoop·分布式
只因只因爆1 天前
mapreduce的工作原理
大数据·linux·hadoop·mapreduce
lix的小鱼1 天前
hadoop集群的常用命令
大数据·linux·hadoop
shouwangV61 天前
hive执行CTAS报错“Hive Runtime Error while processing row”
数据仓库·hive·hadoop
洋芋爱吃芋头1 天前
1. hadoop 集群的常用命令
hadoop
一个天蝎座 白勺 程序猿1 天前
大数据(4.1)Hive架构设计与企业级实战:从内核原理到性能巅峰优化,打造高效数据仓库
数据仓库·hive·hadoop
今天我又学废了1 天前
Spark,配置hadoop集群1
大数据·hadoop·spark