Clickhouse中的预聚合引擎
作者: LemonNan
原文地址: https://mp.weixin.qq.com/s/qXlmGTr4C1NjodXeM4V9pA
注: 转载需注明作者及原文地址
介绍
本文将介绍 Clickhouse 中的 SummingMergeTree
以及 AggregatingMergeTree
预聚合引擎,它们均继承自 MergeTree ,属于 MergeTree 引擎家族,关于 MergeTree 还没有看过的朋友可以先看一下之前的文章:[MergeTree 索引原理],这里就只讨论这两个引擎的使用。
SummingMergeTree
SummingMergeTree 引擎会在数据插入后,定期进行合并,Clickhouse 会将同一个分区内相同主键的数据会合并成一行,如果同时存在多个分区,则非常可能存在多行相同主键的数据,所以在进行查询的时候,需要使用 sum()
以及 group by
进行聚合。一个主键如果对应非常多的数据行,使用 SummingMergeTree 能 非常有效的减少数据存储所占用的空间(仅有预聚合引擎表的情况)以及加快聚合查询。
合并规则
- 默认为除主键外所有的数值类型字段合并求和,列的集合参数由表定义时
SummingMergeTree([columns])
的column 决定,column 字段不允许出现在主键中以及必须为数值类型
,如果建表时没有指定 column ,则默认为除主键外所有的数值类型字段
- 如果合并时所有列中的数据都为0,该主键行数据将会被删除
- 如果列不在主键中,且不在汇总字段中,则从现有的列中随机选一个值
- 不会合并位于主键中的字段
举个
这里拿一个用户的购买记录作为例子,包含字段有:时间、用户id、价格、物品id
数据建表
# 建表sql
create database if not exists test;
create table if not exists test.shopping_record(
`shop_time` DateTime64(3, 'UTC') COMMENT '购买时间',
`user_id` String COMMENT '用户id',
`price` Decimal(6,2) COMMENT '购买价格',
`product_id` String COMMENT '物品id'
) ENGINE = SummingMergeTree(price)
partition by toYYYYMM(shop_time)
order by (toYYYYMMDD(shop_time), user_id)
插入数据
# 用户1购买记录
insert into shopping_record values ('2022-02-23 16:43:33.000','user_1',70,'product_1'),('2022-02-23 16:43:22.000','user_1',20.33,'product_1'),('2022-02-23 17:43:44.000','user_1',433.99,'product_1'),('2022-03-10 18:43:55.000','user_1',76.23,'product_1'),('2022-03-11 19:43:15.000','user_1',99,'product_1'),('2022-03-10 20:43:32.000','user_1',37,'product_1');
这里查看数据,可以看到引擎已经预先聚合了一部分数据
手动合并
执行完手动合并后,再次进行数据的查询,如果数据有合并的话,相同主键的数据会合并进行price求和,由于数据量过小导致查询时结果已经聚合,所以这里多次插入上面的 user_1 的数据
手动合并数据
# 手动合并数据
optimize table shopping_record final;
合并后查询结果
这里展示的是该引擎的自动聚合效果,但是在实际查询的时候,还需要对查询进行 sum
以及 group by
,一部分原因是由于数据可能还没来得及聚合,还有一部分原因是数据可能于多个分区中,此时需要对多个分区进行聚合
-- 由于建表时主键为 toYYYYMMDD(shopping_time),所以这里根据日期来统计
select toYYYYMMDD(shop_time) as day, user_id, sum(price) from shopping_record group by day, user_id order by day
下面是查询结果
新数据插入
这里再增加用户2的购买记录
# 用户2购买记录,这里模拟的时候插入了2次
insert into shopping_record values ('2022-02-23 16:43:33.000','user_2',33.33,'product_1'),('2022-02-24 16:43:22.000','user_2',99.99,'product_2'),('2022-02-26 10:00:00.000','user_2',78.3,'product_3');
执行手动合并sql后进行查询
可以看到数据根据日期以及用户进行了预聚合
AggregatingMergeTree
AggregatingMergeTree 也是预聚合引擎的一种,跟 SummingMergeTree 不同的是 AggregatingMergeTree 可以指定各种聚合函数
,而 SummingMergeTree 只能处理数值求和
的情况。
在使用 AggregatingMergeTree 存储的时候需要使用 state 结尾函数
存储中间状态值
查询的时候使用 merge
结尾函数处理 state
的中间状态值
照样举个
这里拿 “电商平台的书本访问次数以及访问时长” 作为例子
数据建表
# 书本的查看记录
create table if not exists test.book(
`user_id` String COMMENT '用户id',
`book_id` String COMMENT '书本id',
`view_time` Int32 COMMENT '页面查看时间,单位秒',
`create_time` DateTime64(3, 'UTC') COMMENT '创建时间'
) ENGINE = MergeTree()
partition by toYYYYMM(create_time)
order by (create_time, book_id)
# 书本浏览记录的预聚合 AggregatingMergeTree, 这里使用的是物化视图,物化视图很多操作跟普通表相同
CREATE MATERIALIZED VIEW IF NOT EXISTS test.book_mv
engine = AggregatingMergeTree()
partition by day
order by (day, book_id)
as select toYYYYMMDD(create_time) as day,
book_id as book_id,
count() as visit,
sumState(view_time) as sum_view_time
from test.book
group by day, book_id
插入数据
insert into test.book values
('user_1', 'book_1', 100, '2022-02-23 16:00:00'),
('user_2', 'book_1', 112, '2022-02-23 17:35:00'),
('user_1', 'book_1', 94, '2022-02-23 18:05:00'),
('user_1', 'book_1', 67, '2022-02-23 20:05:00'),
('user_1', 'book_1', 30, '2022-02-25 16:00:00'),
('user_1', 'book_2', 245, '2022-02-23 16:10:00'),
('user_1', 'book_2', 39, '2022-02-23 19:10:00'),
('user_2', 'book_2', 78, '2022-02-23 23:17:00'),
('user_2', 'book_2', 60, '2022-03-10 09:49:00'),
('user_2', 'book_3', 30, '2022-03-10 10:49:00'),
('user_2', 'book_4', 44, '2022-03-10 11:49:00'),
('user_2', 'book_5', 75, '2022-03-10 12:49:00'),
('user_2', 'book_6', 20, '2022-03-10 13:49:00');
结果查询
查询原始数据表
# 因为这里是物化视图使用的预聚合引擎,所以查预询预聚合结果的话要查物化视图
select day, book_id, sum(visit), sumMerge(sum_view_time) as view_time from book_mv group by day, book_id order by day, book_id;
预聚合结果如下图
从图里可以看到,预聚合引擎将原始浏览记录聚合成了所需信息,每天每本书的浏览次数、每天每本书总的页面浏览时间
总结
使用聚合引擎在某些统计的情况下,可以很好的节省存储空间(单预聚合引擎表情况下)以及加快数据聚合查找,但是通常会包含两张表, MergeTree 的原始数据表以及包含预聚合引擎的数据表
,两张表的情况下是需要 拿空间换时间
,上面的话就是物化视图持久化预聚合结果,除原始表外占用额外空间,但是查询预聚合引擎表可以加快聚合查询。
最后
欢迎扫描下方二维码或搜索公众号 LemonCode , 一起交流学习!
Clickhouse中的预聚合引擎的更多相关文章
- 转!!MySQL中的存储引擎讲解(InnoDB,MyISAM,Memory等各存储引擎对比)
MySQL中的存储引擎: 1.存储引擎的概念 2.查看MySQL所支持的存储引擎 3.MySQL中几种常用存储引擎的特点 4.存储引擎之间的相互转化 一.存储引擎: 1.存储引擎其实就是如何实现存储数 ...
- 实例介绍Cocos2d-x中Box2D物理引擎:HelloBox2D
我们通过一个实例介绍一下,在Cocos2d-x 3.x中使用Box2D物理引擎的开发过程,熟悉这些API的使用.这个实例运行后的场景如图所示,当场景启动后,玩家可以触摸点击屏幕,每次触摸时候,就会在触 ...
- 在QT中使用Irrlicht引擎的方法与步骤
Ø 相关库,插件安装部分 本篇文档介绍在Qt5.2.0下面使用lrrlicht引擎在Qt窗口中输出(开发环境:vs2012) 1. 首先安装好Qt5.2.0,下载地址: http://downlo ...
- Express ( MiddleWare/中间件 路由 在 Express 中使用模板引擎 常用API
A fast, un-opinionated, minimalist web framework for Node.js applications. In general, prefer simply ...
- MySql中innodb存储引擎事务日志详解
分析下MySql中innodb存储引擎是如何通过日志来实现事务的? Mysql会最大程度的使用缓存机制来提高数据库的访问效率,但是万一数据库发生断电,因为缓存的数据没有写入磁盘,导致缓存在内存中的数据 ...
- Gtk-WARNING**:无法在模块路径中找到主题引擎:“pixmap”的解决
Gtk-WARNING**:无法在模块路径中找到主题引擎:“pixmap”的解决 解决以上问题, 只需要安装 gnome-themes-standard 即可 如果终端中提示: (gvim:23 ...
- docker swarm英文文档学习-5-在swarm模式中运行Docker引擎
Run Docker Engine in swarm mode在swarm模式中运行Docker引擎 当你第一次安装并开始使用Docker引擎时,默认情况下禁用swarm模式.在启用集群模式时,需要处 ...
- MYSQL中的BlackHole引擎
MYSQL中的BlackHole引擎 http://blog.csdn.net/ylspirit/article/details/7234021 http://blog.chinaunix.net/u ...
- 纸壳CMS3.0中的规则引擎,表达式计算
纸壳CMS3.0中的规则引擎,用于计算通用表达试结果.通常业务逻辑总是复杂多变的,使用这个规则引擎可以灵活的修改计算表达式. IRuleManager IRuleManager,是使用规则引擎的主要接 ...
随机推荐
- android 如何动态设置View的margin和padding
感谢大佬:https://blog.csdn.net/a107494639/article/details/7341077 1.动态设置padding,拿ImageView为例: ImageView ...
- 模仿系统的UIImageView
整体思路: 我们想要模仿系统的UIImageView,我们必须得要知道系统的UIView怎么用. 系统的用法是创建一个UIImageView对象,设置frame,给它传递一个UIIma ...
- docker基础——2.镜像管理
1. Docker镜像的主要特点 (1) 采用分层构建机制. 最底层为bootfs,用于系统引导的文件系统,包括bootloader和kernel,容器启动后会被卸载以节约资源. 其上为rootfs, ...
- 【BZOJ2820】YY的GCD(莫比乌斯反演 数论分块)
题目链接 大意 给定多组\(N\),\(M\),求\(1\le x\le N,1\le y\le M\)并且\(Gcd(x, y)\)为质数的\((x, y)\)有多少对. 思路 我们设\(f(i)\ ...
- Python支付宝单笔转账接口
开发信息 接口加签方式为证书模式 证书模式好处是可以使用支付宝的转账到支付宝账户,也就是提现功能,公钥模式不能实现转账到支付宝账户. 此DEMO利用单笔转账到支付宝账户接口[提现功能]用户可以通过此D ...
- 框架4--NFS网络共享
目录 框架4--NFS网络共享 1.练习 2.昨日问题 3.今日内容 4.NFS简介 5.NFS应用 6.NFS实践 6.1.服务端 6.2.客户端 7.NFS配置详解 8.搭建考试系统 8.1.搭建 ...
- Solution -「CodeChef JUMP」Jump Mission
\(\mathcal{Description}\) Link. 有 \(n\) 个编号 \(1\sim n\) 的格子排成一排,并有三个权值序列 \(\{a_n\},\{h_n\},\{p_n ...
- LNK善意利用
lnk lnk在Windows平台下是快捷方式,可以指向其他目录下的文件,并且可以传递参数.现在有些恶意活动会恶意利用lnk,执行恶意代码. 关于lnk的格式,可以使用010 editor的模 ...
- 使用Flask开发简单接口
作为测试人员,在工作或者学习的过程中,有时会没有可以调用的现成的接口,导致我们的代码没法调试跑通的情况. 这时,我们使用python中的web框架Flask就可以很方便的编写简单的接口,用于调用或调试 ...
- 如何把Spring学精通了?
作为 Java 后端工程师,几乎都要用到 Spring,今天这篇文章是和大家说说如何学好 Spring. 在之前的一篇 Java 读书路线的文章中,我介绍过 Spring 的读书路线: 虽然 Spri ...