作者: 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中的预聚合引擎的更多相关文章

  1. 转!!MySQL中的存储引擎讲解(InnoDB,MyISAM,Memory等各存储引擎对比)

    MySQL中的存储引擎: 1.存储引擎的概念 2.查看MySQL所支持的存储引擎 3.MySQL中几种常用存储引擎的特点 4.存储引擎之间的相互转化 一.存储引擎: 1.存储引擎其实就是如何实现存储数 ...

  2. 实例介绍Cocos2d-x中Box2D物理引擎:HelloBox2D

    我们通过一个实例介绍一下,在Cocos2d-x 3.x中使用Box2D物理引擎的开发过程,熟悉这些API的使用.这个实例运行后的场景如图所示,当场景启动后,玩家可以触摸点击屏幕,每次触摸时候,就会在触 ...

  3. 在QT中使用Irrlicht引擎的方法与步骤

      Ø 相关库,插件安装部分 本篇文档介绍在Qt5.2.0下面使用lrrlicht引擎在Qt窗口中输出(开发环境:vs2012) 1. 首先安装好Qt5.2.0,下载地址: http://downlo ...

  4. Express ( MiddleWare/中间件 路由 在 Express 中使用模板引擎 常用API

    A fast, un-opinionated, minimalist web framework for Node.js applications. In general, prefer simply ...

  5. MySql中innodb存储引擎事务日志详解

    分析下MySql中innodb存储引擎是如何通过日志来实现事务的? Mysql会最大程度的使用缓存机制来提高数据库的访问效率,但是万一数据库发生断电,因为缓存的数据没有写入磁盘,导致缓存在内存中的数据 ...

  6. Gtk-WARNING**:无法在模块路径中找到主题引擎:“pixmap”的解决

    Gtk-WARNING**:无法在模块路径中找到主题引擎:“pixmap”的解决  解决以上问题, 只需要安装 gnome-themes-standard 即可 如果终端中提示:   (gvim:23 ...

  7. docker swarm英文文档学习-5-在swarm模式中运行Docker引擎

    Run Docker Engine in swarm mode在swarm模式中运行Docker引擎 当你第一次安装并开始使用Docker引擎时,默认情况下禁用swarm模式.在启用集群模式时,需要处 ...

  8. MYSQL中的BlackHole引擎

    MYSQL中的BlackHole引擎 http://blog.csdn.net/ylspirit/article/details/7234021 http://blog.chinaunix.net/u ...

  9. 纸壳CMS3.0中的规则引擎,表达式计算

    纸壳CMS3.0中的规则引擎,用于计算通用表达试结果.通常业务逻辑总是复杂多变的,使用这个规则引擎可以灵活的修改计算表达式. IRuleManager IRuleManager,是使用规则引擎的主要接 ...

随机推荐

  1. File 类的 getPath()、getAbsolutePath()、getCanonicalPath() 的区别【转】

    File 类的 getPath().getAbsolutePath().getCanonicalPath() 的区别 感谢大佬:https://blog.csdn.net/zsensei/articl ...

  2. CSS网页使用Font Awesome图标字体时,css定义 content 属性

    原文地址: http://blog.csdn.net/laurel_y/article/details/70842157

  3. Redis高可用(持久化、主从复制、哨兵、集群)

    Redis高可用(持久化.主从复制.哨兵.集群) 目录 Redis高可用(持久化.主从复制.哨兵.集群) 一.Redis高可用 1. Redis高可用概述 2. Redis高可用策略 二.Redis持 ...

  4. cloudstack-4.1.5版本最全入门笔记【2022】

    cloudstack简介 CloudStack是一个开源的具有高可用性及扩展性的云计算平台.目前Cloudstack支持管理大部分主流的hypervisors,如KVM,XenServer,VMwar ...

  5. 晋升挂了!leader说不是我技术不行

    大家好,我是对白. 今天给大家分享一位朋友在互联网大厂晋升失败的故事,不是每一位校招生第一年都可以稳稳晋升的,这不仅取决于你的业务收益,还取决于你是否会包装自己的项目,以下为原文. 晋升 去年秋季,我 ...

  6. 基于6U VPX TMS320C6678+XC7K325T 的信号处理板

    一.板卡概述 本板卡基于6U VPX结构设计无线电信号处理平台.板卡包含1片C6678芯片,1片 FPGA XC7K325T-2FFG900I:4路AD,4路DA:三个双排插针接口,要求承接前端射频电 ...

  7. 用python的turtle作图(二)动画吃豆人

    本文是用python的turtle作图的第二篇,通过这个例子可以了解动画的原理,用python自带的turtle库制作一些小动画. 1.问题描述 在上一篇"用python的turtle作图( ...

  8. Solution -「洛谷 P4194」矩阵

    \(\mathcal{Description}\)   Link.   给定一个 \(n\times m\) 的矩阵 \(A\),构造一个 \(n\times m\) 的矩阵 \(B\),s.t. \ ...

  9. Solution -「LOCAL」逃生

    \(\mathcal{Description}\)   有 \(n\) 个人掉进了深度为 \(h\) 的坑里,第 \(i\) 个人的肩高为 \(a_i\),臂长为 \(b_i\).设当前坑里人的集合为 ...

  10. Cesium 加载地形数据

    1.注册Cesium Ion账号,注册地址:Sign In | Cesium ion 否则,加载数据会报错{code: "InvalidCredentials", message: ...