新型MPP的Doris数据库:数据模型和数据分区使用详解
Apache Doris是一个现代化的MPP分析性数据库产品。是一个由百度开源,在2018年贡献给Apache基金会,成为有顶级开源项目。仅需要亚秒级响应时间即可获得查询结果,可以有效地支持实时数据分析。Apache Doris可以满足多种数据分析需求,如数仓T+1模式固定历史报表,实时数据分析等。
数据模型:
Doris中的字段类型:
TINYINT
1字节
范围:-2^7 + 1 ~ 2^7 - 1
SMALLINT
2字节
范围:-2^15 + 1 ~ 2^15 - 1
BIGINT
8字节
范围:-2^63 + 1 ~ 2^63 - 1
LARGEINT
16字节
范围:-2^127 + 1 ~ 2^127 - 1
FLOAT
4字节
支持科学计数法
DOUBLE
12字节
支持科学计数法
DECIMAL[(precision, scale)]
16字节
保证精度的小数类型。默认是 DECIMAL(10, 0)
precision: 1 ~ 27
scale: 0 ~ 9
其中整数部分为 1 ~ 18
不支持科学计数法
DATE
3字节
范围:0000-01-01 ~ 9999-12-31
DATETIME
8字节
范围:0000-01-01 00:00:00 ~ 9999-12-31 23:59:59
CHAR[(length)]
定长字符串。长度范围:1 ~ 255。默认为1
VARCHAR[(length)]
变长字符串。长度范围:1 ~ 65533
HLL
1~16385个字节
hll列类型,不需要指定长度和默认值、长度根据数据的聚合
程度系统内控制,并且HLL列只能通过配套的hll_union_agg、Hll_cardinality、hll_hash进行查询或使用
BITMAP
bitmap列类型,不需要指定长度和默认值。表示整型的集合,元素最大支持到2^64 - 1
agg_type
聚合类型,如果不指定,则该列为 key 列。否则,该列为 value 列
SUM、MAX、MIN、REPLACE
概念解读:
在 DORIS 中,数据以表(Table)的形式进行逻辑上的描述。一张表包括行(Row)和列(Column)。Row 即用户的一行数据。Column 用于描述一行数据中不同的字段。
Column 可以分为两大类:Key 和 Value。从业务角度看,Key 和 Value 可以分别对应维度列和指标列。
DORIS 的数据模型主要分为3类:
Duplicate 明细模型
Aggregate 聚合模型
Unique 唯一主键模型
Duplicate 明细模型
明细模型是 DORIS 默认使用的数据模型。该数据模型不会对导入的数据进行任何处理。表中的数据即用户导入的原始数据,主键仅仅是排序字段,在 DUPLICATE KEY 的选择上,我们建议适当的选择前 2-4 列就可以。。
CREATE TABLE session_data
(
visitorid SMALLINT,
sessionid BIGINT,
city CHAR(20),
ip varchar(32)
)
DUPLICATE KEY(visitorid, sessionid)
comment '明细模型建表'
DISTRIBUTED BY HASH(sessionid, visitorid) BUCKETS 10;
这种数据模型适用于既没有聚合需求,又没有主键唯一性约束的原始数据的存储。同时,用户也可以通过物化视图功能功能在这种模型基础上建立聚合视图,因此是一种比较推荐的数据模型。
Aggregate 聚合模型
聚合模型需要用户在建表时显式的将列分为 Key 列和 Value 列。该模型会自动的对 Key 相同的行,在 Value 列上进行聚合操作。
CREATE TABLE site_visit
(
siteid INT,
city SMALLINT,
username VARCHAR(32),
pv BIGINT SUM DEFAULT '0'
)
AGGREGATE KEY(siteid, city, username)
comment '聚合模型表'
DISTRIBUTED BY HASH(siteid) BUCKETS 10;
表中的列按照是否设置了 AggregationType,分为 Key (维度列) 和 Value(指标列)。没有设置 AggregationType 的,如 user_id、date、age ... 等称为 Key,而设置了 AggregationType 的称为 Value。
数据的聚合,在 DORIS 中有如下三个阶段发生:
每一批次数据导入的 ETL 阶段。该阶段会在每一批次导入的数据内部进行聚合。
底层 BE 进行数据 Compaction 的阶段。该阶段,BE 会对已导入的不同批次的数据进行进一步的聚合。
数据查询阶段。在数据查询时,对于查询涉及到的数据,会进行对应的聚合。
数据在不同时间,可能聚合的程度不一致。比如一批数据刚导入时,可能还未与之前已存在的数据进行聚合。但是对于用户而言,用户只能查询到聚合后的数据。即不同的聚合程度对于用户查询而言是透明的。用户需始终认为数据以最终的完成的聚合程度存在,而不应假设某些聚合还未发生。
聚合模型表的局限性就是在count(*) 查询需要扫描大量的数据。
因此,当业务上有频繁的 count(*) 查询时,我们建议用户通过增加一个值恒为 1 的,聚合类型为 SUM 的列来模拟 count(*)。
Unique 唯一主键模型
在某些多维分析场景下,用户更关注的是如何保证 Key 的唯一性,即如何获得 Primary Key 唯一性约束。因此,我们引入了 Unique 的数据模型。该模型本质上是聚合模型的一个特例,也是一种简化的表结构表示方式。
CREATE TABLE sales_order
(
orderid BIGINT,
status TINYINT,
username VARCHAR(32),
amount BIGINT DEFAULT '0'
)
UNIQUE KEY(orderid)
comment '明细去重模型'
DISTRIBUTED BY HASH(orderid) BUCKETS 10;
会根据主键保留唯一条数据,后来的数据会覆盖前一条数据。
数据模型的选择建议
因为数据模型在建表时就已经确定,且无法修改。所以,选择一个合适的数据模型非常重要。
Aggregate 模型可以通过预聚合,极大地降低聚合查询时所需扫描的数据量和查询的计算量,非常适合有固定模式的报表类查询场景。但是该模型对 count(*) 查询很不友好。同时因为固定了 Value 列上的聚合方式,在进行其他类型的聚合查询时,需要考虑语意正确性。
Unique 模型针对需要唯一主键约束的场景,可以保证主键唯一性约束。但是无法利用 ROLLUP 等预聚合带来的查询优势(因为本质是 REPLACE,没有 SUM 这种聚合方式)。
Duplicate 适合任意维度的 Ad-hoc 查询。虽然同样无法利用预聚合的特性,但是不受聚合模型的约束,可以发挥列存模型的优势(只读取相关列,而不需要读取所有 Key 列)。
数据分区
概念解读
Partition & Tablet
在 Doris 的存储引擎中,用户数据首先被划分成若干个分区(Partition),划分的规则通常是按照用户指定的分区列进行范围划分,比如按时间划分。而在每个分区内,数据被进一步的按照Hash的方式分桶,分桶的规则是要找用户指定的分桶列的值进行Hash后分桶。每个分桶就是一个数据分片(Tablet),也是数据划分的最小逻辑单元。
Tablet之间的数据是没有交集的,独立存储的。Tablet也是数据移动、复制等操作的最小物理存储单元。
Partition 可以视为是逻辑上最小的管理单元。数据的导入与删除,都可以或仅能针对一个 Partition 进行。
CREATE TABLE IF NOT EXISTS example_db.expamle_tbl
(
`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 "99999" COMMENT "用户最小停留时间"
)
ENGINE=olap
AGGREGATE KEY(`user_id`, `date`, `timestamp`, `city`, `age`, `sex`)
PARTITION BY RANGE(`date`)
(
PARTITION `p201701` VALUES LESS THAN ("2017-02-01"),
PARTITION `p201702` VALUES LESS THAN ("2017-03-01"),
PARTITION `p201703` VALUES LESS THAN ("2017-04-01")
)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 16
PROPERTIES
(
"replication_num" = "3",
"storage_medium" = "SSD",
"storage_cooldown_time" = "2018-01-01 12:00:00"
);
AGGREGATE KEY 数据模型中,所有没有指定聚合方式(SUM、REPLACE、MAX、MIN)的列视为 Key 列。而其余则为 Value 列。
定义列时,可参照如下建议:
Key 列必须在所有 Value 列之前。
尽量选择整型类型。因为整型类型的计算和查找比较效率远高于字符串。
对于不同长度的整型类型的选择原则,遵循 够用即可。
对于 VARCHAR 和 CHAR 类型的长度,遵循 够用即可。
所有列的总字节长度(包括 Key 和 Value)不能超过 100KB。、
分区与分桶
Doris 支持两层的数据划分。第一层是 Partition,仅支持 Range 的划分方式。第二层是 Bucket(Tablet),仅支持 Hash 的划分方式。
也可以仅使用一层分区。使用一层分区时,只支持 Bucket 划分。
Partition
Partition 列可以指定一列或多列。分区列必须为 KEY 列。多列分区的使用方式在后面 多列分区 小结介绍。
不论分区列是什么类型,在写分区值时,都需要加双引号。
分区列通常为时间列,以方便的管理新旧数据。
分区数量理论上没有上限。
当不使用 Partition 建表时,系统会自动生成一个和表名同名的,全值范围的 Partition。该 Partition 对用户不可见,并且不可删改。
Partition 支持通过 VALUES LESS THAN (...) 仅指定上界,系统会将前一个分区的上界作为该分区的下界,生成一个左闭右开的区间。通过,也支持通过 VALUES [...) 指定同时指定上下界,生成一个左闭右开的区间。
综分区的删除不会改变已存在分区的范围。删除分区可能出现空洞。通过 VALUES LESS THAN 语句增加分区时,分区的下界紧接上一个分区的上界。
不可添加范围重叠的分区。
2.Bucket
如果使用了 Partition,则 DISTRIBUTED ... 语句描述的是数据在各个分区内的划分规则。如果不使用 Partition,则描述的是对整个表的数据的划分规则。
分桶列可以是多列,但必须为 Key 列。分桶列可以和 Partition 列相同或不同。
分桶列的选择,是在 查询吞吐 和 查询并发 之间的一种权衡:
如果选择多个分桶列,则数据分布更均匀。如果一个查询条件不包含所有分桶列的等值条件,那么该查询会触发所有分桶同时扫描,这样查询的吞吐会增加,单个查询的延迟随之降低。这个方式适合大吞吐低并发的查询场景。
如果仅选择一个或少数分桶列,则对应的点查询可以仅触发一个分桶扫描。此时,当多个点查询并发时,这些查询有较大的概率分别触发不同的分桶扫描,各个查询之间的IO影响较小(尤其当不同桶分布在不同磁盘上时),所以这种方式适合高并发的点查询场景。
分桶的数量理论上没有上限。
关于 Partition 和 Bucket 的数量和数据量的建议。
一个表的 Tablet 总数量等于 (Partition num * Bucket num)。
一个表的 Tablet 数量,在不考虑扩容的情况下,推荐略多于整个集群的磁盘数量。
单个 Tablet 的数据量理论上没有上下界,但建议在 1G - 10G 的范围内。如果单个 Tablet 数据量过小,则数据的聚合效果不佳,且元数据管理压力大。如果数据量过大,则不利于副本的迁移、补齐,且会增加 Schema Change 或者 Rollup 操作失败重试的代价(这些操作失败重试的粒度是 Tablet)。
当 Tablet 的数据量原则和数量原则冲突时,建议优先考虑数据量原则。
在建表时,每个分区的 Bucket 数量统一指定。但是在动态增加分区时(ADD PARTITION),可以单独指定新分区的 Bucket 数量。可以利用这个功能方便的应对数据缩小或膨胀。
一个 Partition 的 Bucket 数量一旦指定,不可更改。所以在确定 Bucket 数量时,需要预先考虑集群扩容的情况。比如当前只有 3 台 host,每台 host 有 1 块盘。如果 Bucket 的数量只设置为 3 或更小,那么后期即使再增加机器,也不能提高并发度。
举一些例子:假设在有10台BE,每台BE一块磁盘的情况下。如果一个表总大小为 500MB,则可以考虑4-8个分片。5GB:8-16个。50GB:32个。500GB:建议分区,每个分区大小在 50GB 左右,每个分区16-32个分片。5TB:建议分区,每个分区大小在 50GB 左右,每个分区16-32个分片。
表的数据量可以通过 show data 命令查看,结果除以副本数,即表的数据量。
多列分区
Doris 支持指定多列作为分区列,示例如下:
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")
)
* 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 --> 无法导入
动态分区
动态分区是在Doris0.12版本加入的功能。旨在对表级别的分区实现生命周期管理(TTL),减少用户的使用负担。
目前实现了动态添加分区及动态删除分区的功能
原理:
在某些场景下,用户会将表按照天进行分区划分,每天定时执行例行任务,这时需要使用方手动管理分区,否则可能由于使用方没有创建数据导致失败这给使用方带来额外的维护成本。
在实现方式上,FE会启动一个后台子线程,根据fe.conf中dynamic_partition_enable及dynamic_partition_check_interval_seconds参数决定线程是否启动以及该线程的调度频率。每次调度时,会在注册表中读取动态分区表的属性。
参数
dynamic_partition.enable
是否开启动态分区特性,可指定true或false,默认为true
dynamic_partition.time_unit
动态分区调度的单位,可指定day,week,month。当指定day时格式为yyyyMMDD。当指定week时格式为yyyy_ww,表示属于这一年的第几周。当指定为month时,格式为yyyyMM
dynamic_partition.start
动态分区的开始时间,以当天为准,超过该时间范围的分区将会被删除,如果不填写默认值为Interger.Min_VALUE 即-2147483648
dynamic_partition.end
动态分区的结束时间,以当天为基准,会提前创建N个单位的分区范围
dynamic_partition.prefix
动态创建的分区名前缀
dynamic_partition.buckets
动态创建的分区所对应分桶数量
(1)开启动态分区功能,可以在fe.conf中设置dynamic_partition_enable=true,也可以使用命令进行修改。使用命令进行修改,并dynamic_partition_check_interval_seconds调度时间设置为5秒,意思就是每过5秒根据配置刷新分区。我这里做测试设置为5秒,真实场景可以设置为12小时。
root@doris1:/opt/module# curl --location-trusted -u root:123456 -XGET http://doris1:8030/api/_set_config?dynamic_partition_enable=true
root@doris1:/opt/module# curl --location-trusted -u root:123456 -XGET http://doris1:8030/api/_set_config?dynamic_partition_check_interval_seconds=5
mysql> ADMIN SET FRONTEND CONFIG ("dynamic_partition_enable" = "true");
mysql> ADMIN SET FRONTEND CONFIG ("dynamic_partition_check_interval_seconds"="5");
(2)创建一张调度单位为天,不删除历史分区的动态分区表
create table student_dynamic_partition1
(id int,
time date,
name varchar(50),
age int
)
duplicate key(id,time)
PARTITION BY RANGE(time)()
DISTRIBUTED BY HASH(id) buckets 10
PROPERTIES(
"dynamic_partition.enable" = "true",
"dynamic_partition.time_unit" = "DAY",
"dynamic_partition.end" = "3",
"dynamic_partition.prefix" = "p",
"dynamic_partition.buckets" = "10",
"replication_num" = "1"
);
查看分区表情况 SHOW DYNAMIC PARTITION TABLES,更新最后调度时间
使用命令查看表下的所有分区show partitions from student_dynamic_partition1;
————————————————
版权声明:本文为CSDN博主「HD0do」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/HD0do/article/details/123961421
新型MPP的Doris数据库:数据模型和数据分区使用详解的更多相关文章
- shell编程系列23--shell操作数据库实战之mysql命令参数详解
shell编程系列23--shell操作数据库实战之mysql命令参数详解 mysql命令参数详解 -u 用户名 -p 用户密码 -h 服务器ip地址 -D 连接的数据库 -N 不输出列信息 -B 使 ...
- Oracle数据库中序列(SEQUENCE)的用法详解
Oracle数据库中序列(SEQUENCE)的用法详解 在Oracle数据库中,序列的用途是生成表的主键值,可以在插入语句中引用,也可以通过查询检查当前值,或使序列增至下一个值.本文我们主要介绍了 ...
- mysql用户授权、数据库权限管理、sql语法详解
mysql用户授权.数据库权限管理.sql语法详解 —— NiceCui 某个数据库所有的权限 ALL 后面+ PRIVILEGES SQL 某个数据库 特定的权限SQL mysql 授权语法 SQL ...
- 10.Spark Streaming源码分析:Receiver数据接收全过程详解
原创文章,转载请注明:转载自 听风居士博客(http://www.cnblogs.com/zhouyf/) 在上一篇中介绍了Receiver的整体架构和设计原理,本篇内容主要介绍Receiver在 ...
- ORACLE数据泵使用详解
来源于:http://blog.sina.com.cn/s/blog_490a0c990100wh4y.html http://blog.csdn.net/jojo52013145/article/d ...
- Oracle数据库悲观锁与乐观锁详解
数据的锁定分为两种方法,第一种叫做悲观锁,第二种叫做乐观锁.什么叫悲观锁呢,悲观锁顾名思义,就是对数据的冲突采取一种悲观的态度,也就是说假设数据肯定会冲突,所以在数据开始读取的时候就把数据锁定住.而乐 ...
- mysql数据库,安装 !创建!...详解!
package cn.jiayou; /* 一.mysql? a.MySQL是Web世界中使用最广泛的数据库服务器. SQLite的特点? 1.是轻量级.可嵌入,但不能承受高并发访问,适合桌面和移动应 ...
- Sqoop 导入及导出表数据子集命令详解
Sqoop命令详解 1.import命令 案例1:将mysql表test中的数据导入hive的hivetest表,hive的hivetest表不存在. sqoop import --connect j ...
- MySQL数据库表分区功能详解
1.什么是表分区? mysql数据库中的数据是以文件的形势存在磁盘上的,默认放在/mysql/data下面(可以通过my.cnf中的datadir来查看),一张表主要对应着三个文件,一个是frm存放表 ...
随机推荐
- 使用Nginx中遇到的一个小问题思考
我们知道在现在的网站开发中,随着请求量的快速增长,我们经常会用到负载均衡 以便使用多个网站共同支撑网络的请求,为了能让请求按照一定的规律分配给各个支撑服务器,我们会使用一些负载均衡来对请求进行分发 最 ...
- C++:接送旅客
接送旅客 时间限制:1.00sec 内存限制:128MB 题目描述: 现在,你是一家酒店的员工,你需要帮助这家酒店的旅客运送行李离开酒店.现在,你送顶层开始往下移动,为了减少电梯移动的距 ...
- docker的数据存储
概述 Docker 为容器提供了两种存放数据的资源:由 storage driver 管理的镜像层和容器层:以及Data Volume. store driver Docker镜像的分层结构如下图所示 ...
- c++ 超长整数加法 高精度加法
c++ 超长整数加法 高精度加法 实现思路 不能直接使用加法,因为int和long long都已超出最大数据表示范围 数据读入采用string类型,读入后将数据的每一位存储到vector中 vecto ...
- Python if-else的简单表示
常见写法 a = 1 b = 1 c = 2 if a == b: print("true") elif a == c: print("false") else ...
- 一、shell编程与变量
目录 命令是什么 命令是如何运行的: 基本语法 解释器 注释 如何执行 输入.输出流 重定向 管道符 | 变量 常见Shell变量的类型包括: 变量命名原则 单引号和双引号 反引号 变量作用范围 查看 ...
- 快速全面了解QT软件界面开发技术
快速全面了解QT软件界面开发技术 目录 前言 一. 学习QT可能的目的是什么? 只想体验一下QT? 当前的项目选择了用QT. 为将来做QT技术储备. 二. QT的核心技术优势是什么? QT在软 ...
- python这不是有手就行?——python音频处理基础知识
大家应该都知道声音的基础吧? 啊不知道当我没说吧~~~ 1.声音的基础 2.python读取.wav音频 Python学习交流Q群:660193417#### import wave import s ...
- C# --- SqlserverHelper帮助类、快速实现增删改查
using System;using System.Data; using System.Data.SqlClient; namespace Demo.WorkerService { public c ...
- CentOS7系统DNS主从配置
CentOS7系统DNS主从配置:一.DNS服务器正向解析:1.1 基础环境:主机IP 主机名 操作系统 用途192.168.0.110 master ...