当前位置: 首页 > news >正文

【Doris入门】Doris表模型完全指南:明细、聚合、主键模型的选择与优化技巧

目录

引言

1 Doris数据模型基础概念

1.1 什么是数据模型?

1.2 Doris数据模型概述

1.3 Key列与Value列

2 三种数据模型详解

2.1 Duplicate Key Model(明细模型)

2.1.1 模型简介

2.1.2 工作原理

2.1.3 适用场景

2.1.4 建表示例:

2.2 Aggregate Key Model(聚合模型)

2.2.1 模型简介

2.2.2 聚合类型详解

2.2.3 工作原理

2.2.4 聚合示例

2.2.5 建表示例

2.3 Unique Key Model(主键模型)

2.3.1 模型简介

2.3.2 实现方式

2.3.3 工作原理

2.3.4 与Aggregate模型的关系

2.3.5 建表示例

3 数据模型对比与选择

3.1 三种模型能力对比

3.2 数据模型选择决策流程

3.3 典型应用场景示例

3.3.1 电商系统数据建模

3.3.2 数据仓库分层建模

4 数据模型内部机制

4.1 数据存储结构

4.2 数据模型与存储的关系

4.3 ROLLUP与数据模型

5 实践建议与性能优化

5.1 数据模型选择实践建议

5.2 性能优化建议

5.2.1 Duplicate模型优化

5.2.2 Aggregate模型优化

5.2.3 Unique模型优化

6 总结


引言

Apache Doris作为一款现代化的MPP架构分析型数据库,凭借其高性能、易用性和实时分析能力,在数据仓库和BI分析领域获得了广泛应用。对于Doris初学者来说,理解其数据表模型是掌握Doris的关键第一步。

1 Doris数据模型基础概念

1.1 什么是数据模型?

在数据库领域,数据模型是定义数据如何存储、组织和访问的框架。它决定了数据的逻辑结构、操作约束以及数据之间的关系。对于Doris这样的分析型数据库而言,数据模型直接影响着查询性能、存储效率和数据处理能力。
数据模型的核心作用
  • 定义数据的存储方式
  • 确定数据的组织结构
  • 影响查询性能和效率
  • 决定数据处理的能力和限制

1.2 Doris数据模型概述

  • Doris提供了三种核心数据模型,每种模型都有其特定的适用场景和优势:
Doris三种数据模型的分类关系和核心特点:
  • Duplicate模型:专注于保留原始数据,提供最大的查询灵活性
  • Aggregate模型:通过预聚合提升查询性能,适合固定模式的报表查询
  • Unique模型:保证主键唯一性,支持数据更新和自动去重

1.3 Key列与Value列

在Doris的数据模型中,列被分为Key列和Value列两大类:
  • Key列:也称为维度列,用于数据的分组、排序和去重
  • Value列:也称为指标列,用于存储需要聚合或计算的数值
  • Key列与Value列的关系
  • Key列:包含业务维度信息,如用户ID、时间、地区等,用于数据的组织和管理
  • Value列:包含业务指标信息,如销售额、访问次数等,用于数据分析和计算
  • 两者的分工明确,Key列负责数据的组织,Value列负责数据的计算

2 三种数据模型详解

2.1 Duplicate Key Model(明细模型)

2.1.1 模型简介

Duplicate模型是Doris的默认数据模型,也是最简单的模型。它的核心特点是完全保留原始数据,不会对数据进行任何聚合或去重处理。无论数据是否重复,都会原样存储。
核心特征
  • 保留所有原始数据,不做任何处理
  • 支持任意维度的灵活查询
  • 适合需要详细分析的场景

2.1.2 工作原理

  • Duplicate模型的工作流程:
  • 数据导入阶段:用户将数据导入Doris,系统按照指定的Key列对数据进行排序,但不会进行任何聚合或去重处理
  • 数据存储阶段:数据被原样存储在存储层,完全保留原始格式
  • 数据查询阶段:查询时直接返回原始数据,不进行任何额外处理

2.1.3 适用场景

Duplicate模型特别适合以下场景:
  • 日志分析:需要保留所有原始日志,用于详细的问题排查和分析
  • 审计追踪:必须完整记录所有操作历史,不能丢失任何细节
  • 原始数据存储:作为数据仓库的ODS层,存储原始业务数据
  • 灵活分析:需要进行各种Ad-hoc查询,不受预聚合限制

2.1.4 建表示例

CREATE TABLE IF NOT EXISTS test_db.ods_log_tmp
(`timestamp` DATETIME NOT NULL COMMENT "日志时间",`user_id` BIGINT COMMENT "用户ID",`action` VARCHAR(50) COMMENT "用户操作",`page` VARCHAR(100) COMMENT "访问页面",`duration` INT COMMENT "停留时长"
)
DUPLICATE KEY(`timestamp`, `user_id`)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 10
PROPERTIES ("replication_num" = "1"
);

2.2 Aggregate Key Model(聚合模型)

2.2.1 模型简介

Aggregate模型是Doris最具特色的数据模型,它支持在数据导入时进行预聚合处理。对于Key列相同的行,Value列会按照指定的聚合方式进行自动计算,从而减少存储空间并提升查询性能。
核心特征
  • 支持多种聚合方式(SUM、MAX、MIN、REPLACE等)
  • 预聚合减少数据量,提升查询性能
  • 适合固定模式的报表查询

2.2.2 聚合类型详解

  • Aggregate模型支持多种聚合类型,每种类型都有其特定的用途:
  • SUM:用于需要累加的指标,如销售额、访问次数
  • MAX/MIN:用于需要获取极值的指标,如最高/最低温度
  • REPLACE:用于需要保留最新值的指标,如状态信息
  • REPLACE_IF_NOT_NULL:用于优先保留非空值的场景
  • HLL_UNION:用于去重计数,如统计用户数UV
  • BITMAP_UNION:用于多值属性的合并,如用户标签

2.2.3 工作原理

  • Aggregate模型的聚合过程可以分为三个阶段:
  • 导入阶段聚合:数据导入时,在单个批次内部进行聚合,减少内存占用
  • 合并阶段聚合:在后台Compaction过程中,将多个批次的数据进行合并聚合,优化存储结构
  • 查询阶段聚合:查询时对尚未完全聚合的数据进行最终聚合,保证查询结果的一致性

2.2.4 聚合示例

  • 原始数据

user_id

date

city

cost

visit_time

10001

2025-07-01

北京

100

10

10001

2025-07-01

北京

200

15

10002

2025-07-01

上海

150

20

  • 聚合后数据

user_id

date

city

cost(SUM)

visit_time(MAX)

1001

2025-07-01

北京

300

15

1002

2025-07-01

上海

150

20

聚合过程说明
  • user_id=1001的两行数据被聚合为一行
  • cost列使用SUM聚合:100 + 200 = 300
  • visit_time列使用MAX聚合:max(10, 15) = 15

2.2.5 建表示例

CREATE TABLE IF NOT EXISTS test_db.ads_user_behavior_tmp
(`user_id` BIGINT NOT NULL COMMENT "用户ID",`date` DATE NOT NULL COMMENT "日期",`city` VARCHAR(20) COMMENT "城市",`cost` BIGINT SUM DEFAULT "0" COMMENT "消费金额",`visit_time` INT MAX DEFAULT "0" COMMENT "访问时长"
)
AGGREGATE KEY(`user_id`, `date`, `city`)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 10
PROPERTIES ("replication_num" = "1"
);

2.3 Unique Key Model(主键模型)

2.3.1 模型简介

Unique模型专门用于处理需要主键唯一性约束的场景。它保证对于相同的Key值,只保留最新写入的数据,自动实现数据去重和更新功能。
核心特征
  • 保证主键唯一性
  • 自动保留最新数据
  • 支持数据更新操作
  • 本质是Aggregate模型的特例

2.3.2 实现方式

  • Unique模型提供了两种实现方式,各有优劣:
  • 读时合并:写入时性能高,但查询时性能低,适合写入密集型场景
  • 写时合并:写入时性能稍低,但查询时性能高,适合查询密集型场景
  • 从Doris 2.1版本开始,写时合并成为默认实现方式

2.3.3 工作原理

  • Unique模型的数据更新流程:
  • 首次插入:当插入一个不存在的Key时,直接存储新数据
  • 重复插入:当插入已存在的Key时,自动更新为最新值
  • 数据查询:查询时直接返回该Key对应的最新值,无需额外处理

2.3.4 与Aggregate模型的关系

  • Unique模型本质上是Aggregate模型的一种特例,所有非Key列都使用REPLACE聚合方式:
  • Unique模型可以看作是所有Value列都使用REPLACE聚合的Aggregate模型
  • 这种设计使得Unique模型能够自动保留最新值,简化数据更新操作
  • 特别适合需要主键约束和数据更新的业务场景

2.3.5 建表示例

CREATE TABLE IF NOT EXISTS test_db.dwd_user_info_tmp
(`user_id` BIGINT NOT NULL COMMENT "用户ID",`username` VARCHAR(50) NOT NULL COMMENT "用户名",`city` VARCHAR(20) COMMENT "城市",`age` INT COMMENT "年龄",`register_time` DATETIME COMMENT "注册时间"
)
UNIQUE KEY(`user_id`, `username`)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 10
PROPERTIES("replication_num"="1"
);

3 数据模型对比与选择

3.1 三种模型能力对比

能力特性

Duplicate模型

Aggregate模型

Unique模型

数据去重

不支持

按Key聚合

按Key唯一

明细查询

支持

不支持

支持

聚合查询

性能一般

性能优秀

性能一般

数据更新

不支持

不支持

支持

count(*)性能

优秀

较差

较差

存储空间

较高

较低

中等

写入性能

优秀

良好

良好

查询灵活性

最高

受限

中等

3.2 数据模型选择决策流程

  • 选择合适的数据模型是Doris应用成功的关键:
  • 第一步:判断是否需要保留所有原始数据,如果是则选择Duplicate模型
  • 第二步:如果不需要保留原始数据,判断是否需要主键唯一性约束,如果是则选择Unique模型
  • 第三步:如果不需要主键约束,判断是否需要预聚合优化,如果是则选择Aggregate模型
  • 循环评估:如果都不符合,需要重新评估业务需求

3.3 典型应用场景示例

3.3.1 电商系统数据建模

  • 一个典型的电商系统通常需要处理多种类型的数据,不同类型的数据适合不同的数据模型:
  • 用户行为日志:使用Duplicate模型保留所有行为细节,用于用户行为分析
  • 订单交易数据:使用Unique模型保证订单唯一性,支持订单状态更新
  • 商品统计报表:使用Aggregate模型预聚合数据,提升报表查询性能

3.3.2 数据仓库分层建模

  • 在数据仓库建设中,不同层次的数据适合使用不同的数据模型:
  • ODS层:使用Duplicate模型原样存储业务系统数据
  • DWD层:根据数据特点选择Duplicate或Unique模型,保证数据质量
  • DWS层:使用Aggregate模型进行预聚合,提升查询性能
  • ADS层:使用Aggregate模型提供面向应用的快速查询

4 数据模型内部机制

4.1 数据存储结构

  • Doris采用列式存储,其数据存储结构对理解数据模型的工作原理很重要:
  • Table到Tablet:逻辑表到物理存储单元的映射
  • Rowset:一次导入的数据集合
  • Segment:核心存储单元,包含数据和索引
  • 数据区域:按列存储实际数据,分为多个Page
  • 索引区域:包含前缀索引和Zone Map索引,加速查询

4.2 数据模型与存储的关系

  • 不同的数据模型在存储层有不同的实现方式:
  • Duplicate模型:原样存储所有数据,按Key列排序,不进行聚合处理
  • Aggregate模型:按Key聚合存储,Value列按聚合类型处理,减少存储空间
  • Unique模型:按Key唯一存储,保留最新Value值,本质是REPLACE聚合

4.3 ROLLUP与数据模型

  • ROLLUP是Doris中的预聚合机制,与数据模型密切相关:
  • 基于Duplicate模型:可以创建聚合型ROLLUP,在明细数据基础上进行预聚合
  • 基于Aggregate模型:可以创建更粗粒度的ROLLUP,进一步优化查询性能
  • 基于Unique模型:可以创建聚合型ROLLUP,基于REPLACE聚合进行统计分析
  • 所有ROLLUP的共同目标是提升查询性能

5 实践建议与性能优化

5.1 数据模型选择实践建议

  • 场景分析:分析数据特征,包括是否需要明细数据、是否有主键约束、查询模式等
  • 性能考量:考虑查询性能要求,包括实时性、并发量等
  • 维护成本:考虑数据更新频率、数据量大小、存储成本等
  • 综合决策:基于以上因素选择最合适的数据模型

5.2 性能优化建议

5.2.1 Duplicate模型优化

  • 排序键优化:选择高基数列作为排序键前缀,考虑查询模式,控制排序键长度
  • 分区策略优化:按时间分区,合理设置分区大小,避免产生过多小文件
  • ROLLUP优化:针对常用查询创建聚合ROLLUP,平衡存储空间与查询性能

5.2.2 Aggregate模型优化

  • count(*)优化:添加SUM类型的count列,使用SUM(count)替代count(*),显著提升性能
  • 聚合类型选择:根据业务需求选择合适的聚合类型,避免语义错误,考虑查询需求
  • Key列设计:选择合适的维度组合作为Key列,避免过多Key列,考虑数据分布情况

5.2.3 Unique模型优化

  • 实现方式选择:根据读写比例选择写时合并或读时合并,优先选择写时合并
  • 主键设计:选择合适的主键列,避免过长的主键,考虑唯一性需求
  • 更新策略:优先使用批量更新,合理设置导入频率,避免频繁小批量导入

6 总结

http://www.xdnf.cn/news/1393129.html

相关文章:

  • layout版图设计学习笔记4_Virtuoso基础介绍
  • Altium Designer 22使用笔记(10)---PCB铺铜相关操作
  • 如何解决网关断网后时间不再统计的问题?无RTC子设备如何打通主网关的时间同步功能?
  • Unity EventTrigger 动态添加事件
  • 电商数据的获取方式:API、爬虫、第三方服务及更多
  • 如何使用 Graylog 连接 Easysearch
  • Nginx原理及九大常见故障解决方法
  • idea2025.1.5安装+pj
  • MemoryVLA:让机器人拥有“记忆“的视觉-语言-动作模型
  • 3021. Alice 和 Bob 玩鲜花游戏
  • JSTL!
  • 期权合约作废了怎么处理?
  • STM32之IIC详解
  • IP v 6
  • five86: 2靶场渗透
  • 论文阅读:ICLR 2024 GAIA: A Benchmark for General AI Assistants
  • 嵌入式Linux LED驱动开发
  • Frida-dexdump 使用指南:从内存中脱取安卓 Dex 文件
  • 动态规划--Day03--打家劫舍--198. 打家劫舍,213. 打家劫舍 II,2320. 统计放置房子的方式数
  • 机器人视觉检测
  • 151.翻转字符串里的单词(字符串算法)
  • 昇腾算力加持,深度思考模型Colossal-R1上线魔乐社区
  • 多智能体框架(下)
  • 嵌入式Linux驱动开发 - 蜂鸣器驱动
  • 【前端教程】JavaScript 数组对象遍历与数据展示实战
  • 微功耗遥测终端机在城市管网压力/流量监测中的应用
  • 打造企业内部的“技术桥梁”:超级用户机制如何助力制造企业高效运维
  • 【数据分享】省级人工智能发展水平综合指标体系(2011-2022)
  • 【LeetCode】动态规划——72.编辑距离、10.正则表达式匹配
  • ros2---位姿转换--eigen/tf2