Doris

https://doris.apache.org/zh-CN/docs/dev/data-table/data-model

SHOW FRONTENDS;

SHOW BACKENDS;

SHOW BROKER;

http://192.168.12.39:8030/home

root/123456

MPP:大规模并行处理

FE和BE两种角色,两个进程,不依赖外部组件,FE和BE都可线性扩展

MPP架构的数据库是将任务并行的分散到多个的节点上,进行协同计算,在每个节点将各自的计算任务处理完成之后,再将计算的结果进行汇总,输出最终的结果

FE(Leader,JAVA):存储和维护集群的元数据,负责接收和解析用户的查询请求,规划查询计化,调度查询结果。

FE主要分为三个角色:Leader、Follower、Observer

Leader和Follower主要是用来实现Doris集群的高可用,在Leader宕机之后,Follower节点能够迅速代替Leader的工作,能够实现实时恢复元数据,从而保证对Doris集群不造成任何影响。

Observer是用来拓展查询节点的,同时起到了元数据备份的作用,如果在感知到集群的查询有压力时,可以同通过添加Observer节点来达到提高集群查询的能力,注意:Observer只参与读取,不参与写入

BE(C++):负责物理数据的存储和计算,以及根据FE生成的物理执行计划,然后进行查询(分布式,多节点并行执行查询,统一汇总)。数据的可靠性由BE保证(多副本)

同时BE还会将数据存储为3副本或者多副本(可根据数据的权重以及集群的资源进行合理设置,可以动态调整)。

Broker:broker是一个无状态的进程。其中封装了文件系统的接口,能够为Doris提供访问外部数据源的能力(比如:HDFS、S3等)。通常在每一台节点上部署一个broker的示例即可。

数据源经过各种数据集成和加工处理后,通常会入库到实时数仓 Doris 和离线湖仓(Hive, Iceberg, Hudi 中),Apache Doris 被广泛应用在以下场景中。

Doris整体架构如下图所示,Doris 架构非常简单,只有两类进程

Frontend(FE),主要负责用户请求的接入、查询解析规划、元数据的管理、节点管理相关工作。

FE的磁盘空间主要用户存储元数据,包括日志和image.通常从几百MB到几个G不等。

FE节点至少为1,1个Follower.当部署1个Follower和1个Observer时,可以实现读高可用。当部署3个Follower时候,可实现读写高可用(HA)

Backend(BE),主要负责数据存储、查询计划的执行。

BE的磁盘空间主要用于存放用户数据,总磁盘空间按用户数据量*3(3副本)计算。然后再预留额外40%的空间用作后台compaction以及一些中间数据的存放。

一台机器上可以部署多个BE实例,但是只能部署一个FE. 如果需要三副本数据,那么至少需要3台机器各部署一台BE实例。

在使用接口方面,Doris 采用 MySQL 协议,高度兼容 MySQL 语法,支持标准 SQL,用户可以通过各类客户端工具来访问 Doris,并支持与 BI 工具的无缝对接。

在存储引擎方面,Doris 采用列式存储,按列进行数据的编码压缩和读取,能够实现极高的压缩比,同时减少大量非相关数据的扫描,从而更加有效利用 IO 和 CPU 资源。

在 Doris 中,数据以表(Table)的形式进行逻辑上的描述。 一张表包括行(Row)和列(Column)。Row 即用户的一行数据。Column 用于描述一行数据中不同的字段。

Column 可以分为两大类:Key 和 Value。从业务角度看,Key 和 Value 可以分别对应维度列和指标列。

Column只分为排序列和非排序列。存储引擎会按照排序列队数据进行排序存储,并建立稀疏索引,以便在排序列中进行快速查找。

包管理工具

-rpm -redhat package manager

-yum -yellodog updater modified

Doris支持单分区和复合分区两种建表方式;

1、复合分区,既分区又分桶

2、单分区,只做HASH分布,既只分桶。

properties

在建表语句中指定,副本数强烈建议保持奇数。

最大副本数量取决于集群独立IP的数量,(注意不是BE数量)

ENGINE

engine的类型是olap,既默认的ENGINE类型,在Doris中,只有这个ENGINE类型是由Doris负责数据管理和存储的。

其他ENGINE类型,如mysql,broker,es等等,本质上只是对外部其他数据库或系统中的表的映射。以保证Doris可以读取

这些数据。而Doris本身并不创建、管理和存储任何非OLAP ENGINE类型的表和数据。

Doris 的数据模型主要分为3类:

Aggregate

Unique

DUPLICATE

Aggreate聚合模型,在如下三个阶段发生

1、每一批次数据导入ETL阶段,对于查询涉及到的数据,会进行对应的聚合

2、底层BE进行数据compaction合并的阶段,该阶段,BE会对已导入的不同批次的数据进行进一步的聚合。

3、数据查询阶段,在数据查询时,对于查询涉及到的数据,会进行对应的聚合。数据在不同时间,可能聚合的

程度不一致。比如一批数据刚导入时,可能还未与之前已存在的数据进行聚合。但是对于用户而言,用户只能查询

到聚合后的数据,既不同的聚合程度对于用户查询而言是透明的。用户需始终认为数据以最终的完成的聚合程度存在,

而不应假设某些聚合还未发生。

查询到的结果一定是聚合后的结果。

适合固定模式的报表类查询场景。固定value列上的聚合方式。

select count(*) from table;不适合。可用增加一恒定列值为1的字段,用sum。

Uniq 模型唯一模型

在某些多维分析场景下,用户更关注的是如何保证Key的唯一性。该模型本质上是聚合模型的一种特例。

Uniq模型

key保证唯一,value数据则进行更新。其他字段进行replace,update;

适合需要对唯一主键约束的场景,可以保证组建唯一性约束。

Duplicate模型 明细模型

数据既没有组件,也没有聚合需求。不会进行任何聚合,即使两行数据完全相同,也都会保留。

duplicate key(userid,username) 方便BE底层数据进行稀疏索引。对用户无感。

适合任意维度的AD-HOC查询,可以发挥列存模型的优势。

#Aggregate 模型 1 (聚合模型的实现方式是读时合并(merge on read))

DROP TABLE example_tbl;

CREATE TABLE IF NOT EXISTS example_tbl

(

`user_id` LARGEINT NOT NULL COMMENT "用户id",

`date` DATE 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 "用户最小停留时间"

)

AGGREGATE KEY(`user_id`, `date`, `city`, `age`, `sex`)

DISTRIBUTED BY HASH(`user_id`) BUCKETS 1

PROPERTIES (

"replication_allocation" = "tag.location.default: 1"

);

INSERT INTO example_tbl(user_id,DATE,city,age,sex,last_visit_date,cost,max_dwell_time,min_dwell_time)

VALUES

(10000,'2017-10-01','北京',20,0,'2017-10-01 07:00:00',35,10,2),

(10000,'2017-10-01','北京',20,0,'2017-10-01 17:05:45',15,22,22);

SELECT * FROM example_tbl;

#会针对AGGREGATE KEY中(`user_id`, `date`, `city`, `age`, `sex`) 做聚合处理

只要保证导入的数据中,每一行的 Key 都不完全相同,那么即使在聚合模型下,Doris 也可以保存完整的明细数据。

#Aggregate 模型 1

数据的聚合,在 Doris 中有如下三个阶段发生:

每一批次数据导入的 ETL 阶段。该阶段会在每一批次导入的数据内部进行聚合。

底层 BE 进行数据 Compaction 的阶段。该阶段,BE 会对已导入的不同批次的数据进行进一步的聚合。

数据查询阶段。在数据查询时,对于查询涉及到的数据,会进行对应的聚合。

#Unique 模型 1

在某些多维分析场景下,用户更关注的是如何保证 Key 的唯一性,即如何获得 Primary Key 唯一性约束。

因此,我们引入了 Unique 数据模型。在1.2版本之前,该模型本质上是聚合模型的一个特例,也是一种简化的表结构表示方式。由于聚合模型的实现方式是读时合并(merge on READ)

,因此在一些聚合查询上性能不佳(参考后续章节聚合模型的局限性的描述),在1.2版本我们引入了Unique模型新的实现方式,写时合并(merge on WRITE

写时合并将在未来替换读时合并成为Unique模型的默认实现方式,两者将会短暂的共存一段时间。

DROP TABLE example_tbl;

CREATE TABLE IF NOT EXISTS example_tbl

(

`user_id` LARGEINT NOT NULL COMMENT "用户id",

`username` VARCHAR(50) NOT NULL COMMENT "用户昵称",

`city` VARCHAR(20) COMMENT "用户所在城市",

`age` SMALLINT COMMENT "用户年龄",

`sex` TINYINT COMMENT "用户性别",

`phone` LARGEINT COMMENT "用户电话",

`address` VARCHAR(500) COMMENT "用户地址",

`register_time` DATETIME COMMENT "用户注册时间"

)

UNIQUE KEY(`user_id`, `username`)

DISTRIBUTED BY HASH(`user_id`) BUCKETS 1

PROPERTIES (

"replication_allocation" = "tag.location.default: 1"

);

INSERT INTO example_tbl(user_id,username,city,age,sex,phone,address,register_time)

VALUES

(10000,'胡博维','北京',20,0,'13728788257','我是地址','2023-2-24 17:20:24'),

(10000,'胡博维','北京1',21,1,'13728788258','我是地址1','2023-2-25 17:20:24');

SELECT * FROM example_tbl;

#会根据唯一索引就行合并 取最后一条数据值

#即Unique 模型的读时合并实现完全可以用聚合模型中的 REPLACE 方式替代。其内部的实现方式和数据存储方式也完全一样

写时合并

Unqiue模型的写时合并实现,与聚合模型就是完全不同的两种模型了,查询性能更接近于duplicate模型,在有主键约束需求的场景上相比聚合模型有较大的查询性能优势,

尤其是在聚合查询以及需要用索引过滤大量数据的查询中。

DROP TABLE example_tbl;

CREATE TABLE IF NOT EXISTS example_tbl

(

`user_id` LARGEINT NOT NULL COMMENT "用户id",

`username` VARCHAR(50) NOT NULL COMMENT "用户昵称",

`city` VARCHAR(20) COMMENT "用户所在城市",

`age` SMALLINT COMMENT "用户年龄",

`sex` TINYINT COMMENT "用户性别",

`phone` LARGEINT COMMENT "用户电话",

`address` VARCHAR(500) COMMENT "用户地址",

`register_time` DATETIME COMMENT "用户注册时间"

)

UNIQUE KEY(`user_id`, `username`)

DISTRIBUTED BY HASH(`user_id`) BUCKETS 1

PROPERTIES (

"replication_allocation" = "tag.location.default: 1",

"enable_unique_key_merge_on_write" = "true"

);

INSERT INTO example_tbl(user_id,username,city,age,sex,phone,address,register_time)

VALUES

(10000,'胡博维','北京',20,0,'13728788257','我是地址','2023-2-24 17:20:24'),

(10000,'胡博维','北京1',21,1,'13728788258','我是地址1','2023-2-25 17:20:24');

SELECT * FROM example_tbl;

# Duplicate 模型 1

在某些多维分析场景下,数据既没有主键,也没有聚合需求。因此,我们引入 Duplicate 数据模型来满足这类需求。举例说明。

DROP TABLE example_tbl;

CREATE TABLE IF NOT EXISTS example_tbl

(

`timestamp` DATETIME NOT NULL COMMENT "日志时间",

`type` INT NOT NULL COMMENT "日志类型",

`error_code` INT COMMENT "错误码",

`error_msg` VARCHAR(1024) COMMENT "错误详细信息",

`op_id` BIGINT COMMENT "负责人id",

`op_time` DATETIME COMMENT "处理时间"

)

DUPLICATE KEY(`timestamp`, `type`, `error_code`)

DISTRIBUTED BY HASH(`type`) BUCKETS 1

PROPERTIES (

"replication_allocation" = "tag.location.default: 1"

);

INSERT INTO example_tbl(timestamp,type,error_code,error_msg,op_id,op_time)

VALUES

('2023-2-24 17:20:24',28,1,'errormessage',1,'2023-2-24 17:20:24'),

('2023-2-24 17:20:24',20,2,'errormessage',1,'2023-2-25 17:20:24');

SELECT * FROM example_tbl;

这种数据模型区别于 Aggregate 和 Unique 模型。数据完全按照导入文件中的数据进行存储,不会有任何聚合。即使两行数据完全相同,也都会保留。

而在建表语句中指定的 DUPLICATE KEY,只是用来指明底层数据按照那些列进行排序。(更贴切的名称应该为 “Sorted Column”,这里取名 “DUPLICATE KEY” 只是用以明确表示所用的数据模型。

关于 “Sorted Column”的更多解释,可以参阅前缀索引)。在 DUPLICATE KEY 的选择上,我们建议适当的选择前 2-4 列就可以。

这种数据模型适用于既没有聚合需求,又没有主键唯一性约束的原始数据的存储。

Duplicate 模型

Duplicate 模型没有聚合模型的这个局限性。因为该模型不涉及聚合语意,在做 count(*) 查询时,任意选择一列查询,即可得到语意正确的结果。

key 列

Duplicate、Aggregate、Unique 模型,都会在建表指定 key 列,然而实际上是有所区别的:对于 Duplicate 模型,表的key列,可以认为只是 “排序列”,并非起到唯一标识的作用。

而 Aggregate、Unique 模型这种聚合类型的表,key 列是兼顾 “排序列” 和 “唯一标识列”,是真正意义上的“ key 列”。

数据模型的选择建议

因为数据模型在建表时就已经确定,且无法修改。所以,选择一个合适的数据模型非常重要。

Aggregate 模型可以通过预聚合,极大地降低聚合查询时所需扫描的数据量和查询的计算量,非常适合有固定模式的报表类查询场景。但是该模型对 count(*) 查询很不友好。同时因为固定了 Value 列上的聚合方式,在进行其他类型的聚合查询时,需要考虑语意正确性。

Unique 模型针对需要唯一主键约束的场景,可以保证主键唯一性约束。但是无法利用 ROLLUP 等预聚合带来的查询优势。

对于聚合查询有较高性能需求的用户,推荐使用自1.2版本加入的写时合并实现。

Unique 模型仅支持整行更新,如果用户既需要唯一主键约束,又需要更新部分列(例如将多张源表导入到一张 doris 表的情形),则可以考虑使用 Aggregate 模型,同时将非主键列的聚合类型设置为 REPLACE_IF_NOT_NULL。具体的用法可以参考语法手册

Duplicate 适合任意维度的 Ad-hoc 查询。虽然同样无法利用预聚合的特性,但是不受聚合模型的约束,可以发挥列存模型的优势(只读取相关列,而不需要读取所有 Key 列)。

编辑此页

#########################################################################

数据划分

本文档主要介绍 Doris 的建表和数据划分,以及建表操作中可能遇到的问题和解决方法。

基本概念

在 Doris 中,数据都以表(Table)的形式进行逻辑上的描述。

Row & Column

一张表包括行(Row)和列(Column):

Row:即用户的一行数据;

Column: 用于描述一行数据中不同的字段。

Column 可以分为两大类:Key 和 Value。从业务角度看,Key 和 Value 可以分别对应维度列和指标列。从聚合模型的角度来说,Key 列相同的行,会聚合成一行。

其中 Value 列的聚合方式由用户在建表时指定。关于更多聚合模型的介绍,可以参阅 Doris 数据模型。

key 列

Duplicate、Aggregate、Unique 模型,都会在建表指定 key 列,然而实际上是有所区别的:对于 Duplicate 模型,表的key列,可以认为只是 “排序列”,并非起到唯一标识的作用。

而 Aggregate、Unique 模型这种聚合类型的表,key 列是兼顾 “排序列” 和 “唯一标识列”,是真正意义上的“ key 列”。

在 count() 查询中,Doris 必须扫描所有的 AGGREGATE KEY 列(这里就是 user_id 和 date),并且聚合后,才能得到语意正确的结果。当聚合列非常多时,count() 查询需要扫描大量的数据。

SHOW DATA;

SHOW DATABASES;

SHOW TABLES;

DESC PCA_RAW_DATA;

desc PCA_RAW_DATA all;

SELECT COUNT(*) FROM PCA_RAW_DATA;

SELECT * FROM PCA_RAW_DATA LIMIT 100;

#######################AGGREGATE KEY模型可以提前聚合数据, 适合报表和多维分析业务。

AGGREGATE KEY相同时,新旧记录进行聚合,目前支持的聚合函数有SUM, MIN, MAX, REPLACE。

DROP TABLE site_visit;

CREATE TABLE site_visit

(

siteid INT,

city SMALLINT,

username VARCHAR(32),

pv BIGINT SUM DEFAULT '0'

)

AGGREGATE KEY(siteid, city, username)

DISTRIBUTED BY HASH(siteid) BUCKETS 10;

INSERT INTO site_visit(siteid,city,username,pv) VALUES

(1,1,'hu',2),

(1,1,'hu',5);

SELECT * FROM site_visit;

##################UNIQUE KEY 相同时,新记录覆盖旧记录。

UNIQUE KEY 相同时,新记录覆盖旧记录。在1.2版本之前,UNIQUE KEY 实现上和 AGGREGATE KEY 的 REPLACE 聚合方法一样,二者本质上相同

,自1.2版本我们给UNIQUE KEY引入了merge on WRITE

DROP TABLE sales_order;

CREATE TABLE sales_order

(

orderid BIGINT,

status TINYINT,

username VARCHAR(32),

amount BIGINT DEFAULT '0'

)

UNIQUE KEY(orderid)

DISTRIBUTED BY HASH(orderid) BUCKETS 10;

INSERT INTO sales_order(orderid,status,username,amount) VALUES

(1,1,'hu',2),

(1,2,'hu1',3);

SELECT * FROM sales_order;

################################## DUPLICATE KEY 只指定排序列,相同的行不会合并。适用于数据无需提前聚合的分析业务。

DROP TABLE session_data;

CREATE TABLE session_data

(

visitorid SMALLINT,

sessionid BIGINT,

visittime DATETIME,

city CHAR(20),

province CHAR(20),

ip varchar(32),

brower CHAR(20),

url VARCHAR(1024)

)

DUPLICATE KEY(visitorid, sessionid)

DISTRIBUTED BY HASH(sessionid, visitorid) BUCKETS 10;

INSERT INTO session_data(visitorid,sessionid,visittime,city) VALUES

(1,1,'2023-2-27 15:36:37','2'),

(2,2,'2023-2-27 15:36:39','3'),

(3,3,'2023-2-27 15:36:36','4');

SELECT * FROM session_data ORDER BY visitorid;

最佳实践

建表

数据模型选择

Doris 数据模型上目前分为三类: AGGREGATE KEY, UNIQUE KEY, DUPLICATE KEY。三种模型中数据都是按KEY进行排序。

AGGREGATE KEY

AGGREGATE KEY相同时,新旧记录进行聚合,目前支持的聚合函数有SUM, MIN, MAX, REPLACE。

AGGREGATE KEY模型可以提前聚合数据, 适合报表和多维分析业务。

CREATE TABLE site_visit

(

siteid INT,

city SMALLINT,

username VARCHAR(32),

pv BIGINT SUM DEFAULT '0'

)

AGGREGATE KEY(siteid, city, username)

DISTRIBUTED BY HASH(siteid) BUCKETS 10;

UNIQUE KEY

UNIQUE KEY 相同时,新记录覆盖旧记录。在1.2版本之前,UNIQUE KEY 实现上和 AGGREGATE KEY 的 REPLACE 聚合方法一样,二者本质上相同,自1.2版本我们给UNIQUE KEY引入了merge on write实现,该实现有更好的聚合查询性能。适用于有更新需求的分析业务。

CREATE TABLE sales_order

(

orderid BIGINT,

status TINYINT,

username VARCHAR(32),

amount BIGINT DEFAULT '0'

)

UNIQUE KEY(orderid)

DISTRIBUTED BY HASH(orderid) BUCKETS 10;

DUPLICATE KEY

只指定排序列,相同的行不会合并。适用于数据无需提前聚合的分析业务。

CREATE TABLE session_data

(

visitorid SMALLINT,

sessionid BIGINT,

visittime DATETIME,

city CHAR(20),

province CHAR(20),

ip varchar(32),

brower CHAR(20),

url VARCHAR(1024)

)

DUPLICATE KEY(visitorid, sessionid)

DISTRIBUTED BY HASH(sessionid, visitorid) BUCKETS 10;

分区和分桶

Doris 支持两级分区存储, 第一层为分区(partition),目前支持 RANGE 分区和 LIST 分区两种类型, 第二层为 HASH 分桶(bucket)。

分区(partition)

分区用于将数据划分成不同区间, 逻辑上可以理解为将原始表划分成了多个子表。可以方便的按分区对数据进行管理,例如,删除数据时,更加迅速。

RANGE分区

业务上,多数用户会选择采用按时间进行partition, 让时间进行partition有以下好处:

可区分冷热数据

可用上Doris分级存储(SSD + SATA)的功能

LIST分区

业务上,用户可以选择城市或者其他枚举值进行partition。

HASH分桶(bucket)

根据hash值将数据划分成不同的 bucket。

建议采用区分度大的列做分桶, 避免出现数据倾斜

为方便数据恢复, 建议单个 bucket 的 size 不要太大, 保持在 10GB 以内, 所以建表或增加 partition 时请合理考虑 bucket 数目, 其中不同 partition 可指定不同的 buckets 数。

DROP TABLE example_tbl;

-- 建表, 并指定静态列类型, 导入遇到对应列会自动转换成静态列的类型

-- 选择随机分桶方式

DESC TABLE表名; 可查看表结构信息

上卷rollup:获取更粗粒度的聚合结果,rollup表不会影响到基表。

rollup表对用户是不可见的。

desc 表名;查看表结构。

alter table 基表名 add rollup 表名(userid(key列),cost(value列))

注意key必须在value前面。

可通过explain查看执行计划,是否使用到rollup.

explain select userid,sum(cost) from 基表名 group by userid;

使用方式key列放在group by中使用,value列使用聚合函数。注意:聚合方式和基表不能变,否则走不了rollup。

创建的rollup表,在具体使用的时候,无论key列或者value列都可不全部使用。

Doris底层数据存储类似SStable sorted String table的数据结果中,该结构是一种有序的数据结构。可按照指定列进行排序存储。

你可能感兴趣的:(大数据)