Doris基本概念介绍

简介

  • Apache Doris 是一个基于 MPP 架构的高性能、实时的分析型数据库,以极速易用的特点被人们所熟知,仅需亚秒级响应时间即可返回海量数据下的查询结果,不仅可以支持高并发的点查询场景,也能支持高吞吐的复杂分析场景
  • 基于此,Apache Doris 能够较好的满足报表分析、即席查询、统一数仓构建、数据湖联邦查询加速等使用场景,用户可以在此之上构建用户行为分析、AB 实验平台、日志检索分析、用户画像分析、订单分析等应用。
  • Apache Doris 最早是诞生于百度广告报表业务的 Palo 项目,2017 年正式对外开源,2018 年 7 月由百度捐赠给 Apache 基金会进行孵化,之后在 Apache 导师的指导下由孵化器项目管理委员会成员进行孵化和运营。目前 Apache Doris 社区已经聚集了来自不同行业数百家企业的 400 余位贡献者,并且每月活跃贡献者人数也超过 100 位。 2022 年 6 月,Apache Doris 成功从 Apache 孵化器毕业,正式成为 Apache 顶级项目(Top-Level Project,TLP)
  • Apache Doris 如今在中国乃至全球范围内都拥有着广泛的用户群体,截止目前, Apache Doris 已经在全球超过 2000 家企业的生产环境中得到应用,在中国市值或估值排行前 50 的互联网公司中,有超过 80% 长期使用 Apache Doris,包括百度、美团、小米、京东、字节跳动、腾讯、网易、快手、微博、贝壳等。同时在一些传统行业如金融、能源、制造、电信等领域也有着丰富的应用。-基于 Apache Doris 可以构建统一实时数仓。
  • 中文文档地址:https://doris.apache.org/zh-CN/docs/get-starting/quick-start

使用

数据模型

  • 在 Doris 中,数据以表(Table)的形式进行逻辑上的描述
  • 一张表包括行(Row)和列(Column)。Row 即用户的一行数据。Column 用于描述一行数据中不同的字段
  • Column 可以分为两大类:Key 和 Value。从业务角度看,Key 和 Value 可以分别对应维度列和指标列
  • Doris 的数据模型主要分为3类: Aggregate,Unique,Duplicate
aggregate 模型
  • 表中的列按照是否设置了 AggregationType,分为 Key (维度列) 和 Value(指标列)
  • 当我们导入数据时,对于 Key 列相同的行会聚合成一行,而 Value 列会按照设置的 AggregationType 进行聚合
  • 有以下四种聚合方式:
    • SUM:求和,多行的 Value 进行累加。
    • REPLACE:替代,下一批数据中的 Value 会替换之前导入过的行中的 Value。
    • MAX:保留最大值。
    • MIN:保留最小值。
  • 当向表中插入数据时,聚合函数会起作用,经过聚合,Doris 中最终只会存储聚合后的数据
  • 注意:明细数据会丢失,用户不能够再查询到聚合前的明细数据了
  • AGGREGATE KEY 数据模型中,所有没有指定聚合方式(SUM、REPLACE、MAX、MIN)的列视为 Key 列。而其余则为 Value 列
  • 字段定义时遵循以下建议:
    • Key 列必须在所有 Value 列之前
    • 尽量选择整型类型。因为整型类型的计算和查找效率远高于字符串
    • 对于不同长度的整型类型的选择原则,遵循 够用即可
    • 对于 VARCHAR 和 STRING 类型的长度,遵循 够用即可
    • 所有列的总字节长度(包括 Key 和 Value)不能超过 100KB
  • 示例:
DROP TABLE IF EXISTS signal.performance_stats_aggregate;
CREATE TABLE IF NOT EXISTS signal.performance_stats_aggregate
(
    `time_stamp` DATETIME NOT NULL COMMENT "雷达上报时间",
    `region_id` INT NOT NULL COMMENT '路口所属区域编号',
    `intersection_number` INT NOT NULL COMMENT "路口ID",
    `detector_nbr` VARCHAR(16) NOT NULL COMMENT "设备编号",
    `approach` TINYINT NOT NULL COMMENT "进口:0-南向SB,1-西南向SW,2-西向WB,3-西北向NW,4-北向NB,5-东北向NE,6-东向EB,7-东南向SE,9-其他OTHER",
    `movement` TINYINT NOT NULL COMMENT "流向:1-直行THROUGH,2-左转LEFT,3-右转RIGHT,4-掉头U_TURN,5-直左TL,6-直右TR,7-三向TLR,8-左右LR,9-直掉UT_TURN,10-左掉UL_TURN,99-其他OTHER",
    `lane_nbr` TINYINT NOT NULL COMMENT "车道号",
    `detector_zone_nbr` TINYINT REPLACE_IF_NOT_NULL COMMENT '检测区域(线)编号',
    `detector_coil_nbr` TINYINT REPLACE_IF_NOT_NULL COMMENT '线圈编号',
    `stats_period` SMALLINT REPLACE_IF_NOT_NULL DEFAULT "0" COMMENT '单位:秒',
    `traffic_flow` SMALLINT REPLACE_IF_NOT_NULL DEFAULT "0" COMMENT '总流量',
    `avg_speed` Float REPLACE_IF_NOT_NULL DEFAULT "0" COMMENT '平均速度:单位:Km/h',
    `time_share` Float REPLACE_IF_NOT_NULL DEFAULT "0" COMMENT '时间占有率:单位:%',
    `density` Float REPLACE_IF_NOT_NULL DEFAULT "0" COMMENT '空间占有率:单位:%',
    `time_headway` Float REPLACE_IF_NOT_NULL DEFAULT "0" COMMENT '车头时距 单位:s',
    `space_headway` Float REPLACE_IF_NOT_NULL DEFAULT "0" COMMENT '车头间距 单位:m',
    `queue_length` Float REPLACE_IF_NOT_NULL DEFAULT "0" COMMENT '最大排队长度:单位:米',
    `stops` Float REPLACE_IF_NOT_NULL DEFAULT "0" COMMENT '平均停车次数单位:次',
    `delay` Float REPLACE_IF_NOT_NULL DEFAULT "0" COMMENT '平均延误单位:s',
    `travel_time` Float REPLACE_IF_NOT_NULL DEFAULT "0" COMMENT '平均旅行时间:单位:s(只计算进口道,出口道默认0)'
)
AGGREGATE KEY(`time_stamp`, `region_id`, `intersection_number` ,`detector_nbr`, `approach`, `movement`, `lane_nbr`)
DISTRIBUTED BY HASH(`region_id`, `intersection_number`) BUCKETS 1
PROPERTIES (
"replication_allocation" = "tag.location.default: 1"
);
Unique 模型
  • 在某些多维分析场景下,用户更关注的是如何保证 Key 的唯一性,即如何获得 Primary Key 唯一性约束。因此引入了 Unique 的数据模型
  • 该模型本质上是聚合模型的一个特例,也是一种简化的表结构表示方式
  • Unique 模型完全可以用聚合模型中的REPLACE方式替代。其内部的实现方式和数据存储方式也完全一样
  • 示例:
DROP TABLE IF EXISTS signal.traffic_event_unique;
CREATE TABLE IF NOT EXISTS signal.traffic_event_unique
(
    `time_stamp` DATETIME(3) NOT NULL COMMENT "事件状态开始时间",
    `region_id` INT NOT NULL COMMENT '路口所属区域编号',
    `intersection_number` INT NOT NULL COMMENT "路口ID",
    `detector_nbr` VARCHAR(16) NOT NULL COMMENT "设备编号",
    `approach` TINYINT NOT NULL COMMENT "进口:0-南向SB,2-西向WB,4-北向NB,6-东向EB,9-其他OTHER",
    `lane_nbr` TINYINT NOT NULL DEFAULT "0" COMMENT "车道号(部分事件不关联车道赋0)",
    `event_code` TINYINT NOT NULL COMMENT '事件码: 1-拥堵TRAFFIC_CONGESTION,2-逆行REVERSE_DRIVE,3-溢出OVERFLOW,4-排队超限QUEUE_OVERRUN,5-路口锁死LOCKED,99-其他',
    `event_status` TINYINT NOT NULL  COMMENT '事件状态:1-交通事件,2-事件恢复',
    `end_time` DATETIME COMMENT "事件结束时间",
    `duration` SMALLINT DEFAULT "0" COMMENT "事件状态持续时间"
)
UNIQUE KEY(`time_stamp`, `region_id`, `intersection_number`, `detector_nbr`, `approach`, `lane_nbr`, `event_code`, `event_status`)
DISTRIBUTED BY HASH(`region_id`, `intersection_number`) BUCKETS 1
PROPERTIES (
"replication_allocation" = "tag.location.default: 1",
"enable_unique_key_merge_on_write" = "true"
);

Duplicate 模式
  • 在某些多维分析场景下,数据既没有主键,也没有聚合需求。因此,引入 Duplicate 数据模型来满足这类需求
  • 这种数据模型区别于 Aggregate和Unique模型。数据完全按照导入文件中的数据进行存储,不会有任何聚合
  • 即使两行数据完全相同,也都会保留。 而在建表语句中指定的 DUPLICATE KEY,只是用来指明底层数据按照那些列进行排序
  • 示例
DROP TABLE IF EXISTS signal.radar_fault_duplicate;
CREATE TABLE IF NOT EXISTS signal.radar_fault_duplicate
(
    `time_stamp` DATETIME(3) NOT NULL COMMENT "雷达上报时间",
    `region_id` INT NOT NULL COMMENT '路口所属区域编号',
    `intersection_number` INT NOT NULL COMMENT "路口ID",
    `detector_nbr` VARCHAR(16) NOT NULL COMMENT "设备编号",
    `fault_type` VARCHAR(16) COMMENT '故障类型',
    `fault_code` VARCHAR(16) COMMENT '故障码',
)
DUPLICATE KEY(`time_stamp`, `region_id`, `intersection_number`)
DISTRIBUTED BY HASH(`region_id`,`intersection_number`) BUCKETS 1
PROPERTIES (
"replication_allocation" = "tag.location.default: 1"
);

数据划分

  • 在 Doris 的存储引擎中,用户数据被水平划分为若干个数据分片(Tablet,也称作数据分桶)
  • 每个 Tablet 包含若干数据行。各个 Tablet 之间的数据没有交集,并且在物理上是独立存储的
  • 多个 Tablet 在逻辑上归属于不同的分区(Partition)。一个 Tablet 只属于一个 Partition。而一个 Partition 包含若干个 Tablet
  • 因为 Tablet 在物理上是独立存储的,所以可以视为 Partition 在物理上也是独立。Tablet 是数据移动、复制等操作的最小物理存储单元
  • 若干个 Partition 组成一个 Table。Partition 可以视为是逻辑上最小的管理单元。数据的导入与删除,都可以或仅能针对一个 Partition 进行
  • Doris 的建表是一个同步命令,SQL执行完成即返回结果,命令返回成功即表示建表成功
Partition
  • Doris 支持两层的数据划分。第一层是 Partition,支持 Range 和 List 的划分方式
  • Range 是范围,列通常为时间列,以方便的管理新旧数据
  • List分区列支持 BOOLEAN, TINYINT, SMALLINT, INT, BIGINT, LARGEINT, DATE, DATETIME, CHAR, VARCHAR 数据类型,分区值为枚举值。只有当数据为目标分区枚举值其中之一时,才可以命中分区。
  • Partition 列可以指定一列或多列,分区列必须为 KEY 列
  • 不论分区列是什么类型,在写分区值时,都需要加双引号。分区数量理论上没有上限
  • 当不使用 Partition 建表时,系统会自动生成一个和表名同名的,全值范围的Partition。该 Partition 对用户不可见,并且不可删改
  • 创建分区时不可添加范围重叠的分区
  • 也可以仅使用一层分区。使用一层分区时,只支持 Bucket 划分
Bucket
  • Doris 支持两层的数据划分,第二层是 Bucket(Tablet),仅支持 Hash 的划分方式
  • 如果使用了 Partition,则 DISTRIBUTED ... 语句描述的是数据在各个分区内的划分规则。如果不使用 Partition,则描述的是对整个表的数据的划分规则。
  • 分桶列可以是多列,Aggregate 和 Unique 模型必须为 Key 列,Duplicate 模型可以是 key 列和 value 列。分桶列可以和 Partition 列相同或不同。
  • 分桶列的选择,是在 查询吞吐 和 查询并发 之间的一种权衡:
    • 如果选择多个分桶列,则数据分布更均匀。如果一个查询条件不包含所有分桶列的等值条件,那么该查询会触发所有分桶同时扫描,这样查询的吞吐会增加,单个查询的延迟随之降低。这个方式适合大吞吐低并发的查询场景。
    • 如果仅选择一个或少数分桶列,则对应的点查询可以仅触发一个分桶扫描。此时,当多个点查询并发时,这些查询有较大的概率分别触发不同的分桶扫描,各个查询之间的IO影响较小(尤其当不同桶分布在不同磁盘上时),所以这种方式适合高并发的点查询场景。
  • AutoBucket: 根据数据量,计算分桶数。 对于分区表,可以根据历史分区的数据量、机器数、盘数,确定一个分桶。
  • 分桶的数量理论上没有上限

创建库、表

  1. 创建一个数据库
create database demo;
  1. 创建数据表
use demo;

CREATE TABLE IF NOT EXISTS demo.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"
);
  • 14
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

坚持是一种态度

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值