网站开发后怎么进入互联网,扬州鼎盛开发建设有限公司网站,wordpress轻论坛主题,营销管理培训课程培训班clickhouse 强大的 MergeTree 系列引擎令人信服#xff0c;其 ReplacingMergeTree、SummingMergeTree 在数据唯一性和汇总场景中表现非凡。但你是否还有保留最小(大)、平均等预聚合需求#xff0c;甚至在一个模型中既有唯一性语意也有汇总、最小、最大、平均值语意该如何处理…clickhouse 强大的 MergeTree 系列引擎令人信服其 ReplacingMergeTree、SummingMergeTree 在数据唯一性和汇总场景中表现非凡。但你是否还有保留最小(大)、平均等预聚合需求甚至在一个模型中既有唯一性语意也有汇总、最小、最大、平均值语意该如何处理。在 doris 中 Aggregate 数据模型可以轻松解决那么同为头部 AP 数据库的 clickhouse 是否可以随心所欲的定义聚合模型呢
一、AggregatingMergeTree
1.1 基本使用
AggregatingMergeTree 表引擎作为 MergeTree 系列引擎也是遵循其家族的基本逻辑的它能够在合并分区的时候按照预先定义的方式聚合数据。与 ReplacingMergeTree、SummingMergeTree 不同的是表引擎已经内置好了聚合方式用户只能指定字段在分区合并时对字段进行去重或累加AggregatingMergeTree 则进一步开发底层给用户用户需要指定在分区合并时采用何种聚合函数以及针对哪些字段进行计算下面是该引擎的使用方式复刻 doris 官方文档的案例
drop table if exists tbl_agg;
create table if not exists tbl_agg
(user_id String comment 用户id,date datetime comment 数据灌入日期时间,city String comment 用户所在城市,age Int8 comment 用户年龄,sex Int8 comment 用户性别,last_visit_date AggregateFunction(anyLast,DateTime) comment 用户最后一次访问时间,cost AggregateFunction(sum, Int256) comment 用户总消费,max_dwell_time AggregateFunction(max,Int64) comment 用户最大停留时间,min_dwell_time AggregateFunction(min,Int64) comment 用户最小停留时间
) engine AggregatingMergeTree()order by (user_id, date, city, age, sex);AggregateFunction 是 clickhouse 提供的特殊数据类型它能够以二进制的形式存储中间状态结果。其使用方式也十分特殊在定义的时候需要提供聚合方式以及数据类型。常用的聚合方式整理如下
count: 计数非空行数sum: 累加max: 最大值min: 最小值anyLast: 最后一个非空值uniq: 去重计数
当然 clickhouse 提供的聚合函数很多详情可以访问: https://clickhouse.com/docs/en/sql-reference/aggregate-functions/reference
因为 AggregateFunction 是二进制存储的中间结果我们在插入数据时也需要将明文数据转换为 AggregateFunction 可以接受的数据类型clickhouse 为每个聚合函数都提供了转换为 AggregateFunction 类型的 *State 函数
insert into tbl_agg
select 10000,2017-10-01,北京,20,0,anyLastState(toDateTime(2017-10-01 06:00:00)),sumState(toInt256(20)),maxState(toInt64(10)),minState(toInt64(10));insert into tbl_agg
select 10000,2017-10-01,北京,20,0,anyLastState(toDateTime(2017-10-01 07:00:00)),sumState(toInt256(15)),maxState(toInt64(2)),minState(toInt64(2));同理我们在查询是也需要特殊的函数将 AggregateFunction 类型转换为明文类似序列化与反序列区别而查询时需要使用 *Merge 函数
SELECTuser_id,anyLastMerge(last_visit_date) AS last_visit_date,sumMerge(cost) AS cost,maxMerge(max_dwell_time) AS max_dwell_time,minMerge(min_dwell_time) AS min_dwell_time
FROM tbl_agg
GROUP BY user_id
ORDER BY user_id ASCQuery id: 30a237df-6018-42fa-a6a9-1d324e21310d┌─user_id─┬─────last_visit_date─┬─cost─┬─max_dwell_time─┬─min_dwell_time─┐
│ 10000 │ 2017-10-01 06:00:00 │ 35 │ 10 │ 2 │
└─────────┴─────────────────────┴──────┴────────────────┴────────────────┘1 row in set. Elapsed: 0.005 sec.看到这里是否觉得这种方式过于繁琐连正常的数据插入都需要借助 State 函数那么在升级改造时将寸步难行。好在上面的方式并不是主流的方式我们可以借助物化视图来屏蔽 State 过程让数据插入保持原生。
1.2 优化体验
首先我们创建相同结构的普通表作为底表
drop table if exists tbl_agg_basic;
create table if not exists tbl_agg_basic
(user_id String comment 用户id,date datetime comment 数据灌入日期时间,city String comment 用户所在城市,age Int8 comment 用户年龄,sex Int8 comment 用户性别,last_visit_date datetime comment 用户最后一次访问时间,cost Int256 comment 用户总消费,max_dwell_time Int64 comment 用户最大停留时间,min_dwell_time Int64 comment 用户最小停留时间
) engine MergeTreeorder by (user_id, date, city, age, sex);之后我们将 State 过程写入物化视图中
drop table if exists mv_tbl_agg;
create materialized view if not exists mv_tbl_agg to tbl_agg
as
select user_id,date,city,age,sex,anyLastState(last_visit_date) as last_visit_date,sumState(cost) as cost,maxState(max_dwell_time) as max_dwell_time,minState(min_dwell_time) as min_dwell_time
from tbl_agg_basic
group by user_id, date, city, age, sex;对用户来说将明细数据优雅的写入底表中tbl_agg 对外提供查询功能用户无需关系数据怎么序列化 下面我们只需要假装什么都不知道向明细数据表插入数据
insert into tbl_agg_basic
values (10000, 2017-10-01, 北京, 20, 0, 2017-10-01 06:00:00, 20, 10, 10),(10000, 2017-10-01, 北京, 20, 0, 2017-10-01 07:00:00, 15, 2, 2),(10001, 2017-10-01, 北京, 30, 1, 2017-10-01 17:05:45, 2, 22, 22),(10002, 2017-10-02, 上海, 20, 1, 2017-10-02 12:59:12, 200, 5, 5),(10003, 2017-10-02, 广州, 32, 0, 2017-10-02 11:20:00, 30, 11, 11),(10004, 2017-10-01, 深圳, 35, 0, 2017-10-01 10:00:15, 100, 3, 3),(10004, 2017-10-03, 深圳, 35, 0, 2017-10-03 10:20:22, 11, 6, 6);数据会自动同步到 tbl_agg 中在查询时我们只需要面向 tbl_agg 此时会比直接查询 tbl_agg_basic 有更高的性能
SELECTuser_id,date,city,age,sex,anyLastMerge(last_visit_date) AS last_visit_date,sumMerge(cost) AS cost,maxMerge(max_dwell_time) AS max_dwell_time,minMerge(min_dwell_time) AS min_dwell_time
FROM tbl_agg
GROUP BYuser_id,date,city,age,sex
ORDER BY user_id ASCQuery id: 6f7fd017-9378-4f42-8c20-56bd711487d1┌─user_id─┬────────────────date─┬─city─┬─age─┬─sex─┬─────last_visit_date─┬─cost─┬─max_dwell_time─┬─min_dwell_time─┐
│ 10000 │ 2017-10-01 00:00:00 │ 北京 │ 20 │ 0 │ 2017-10-01 07:00:00 │ 35 │ 10 │ 2 │
│ 10001 │ 2017-10-01 00:00:00 │ 北京 │ 30 │ 1 │ 2017-10-01 17:05:45 │ 2 │ 22 │ 22 │
│ 10002 │ 2017-10-02 00:00:00 │ 上海 │ 20 │ 1 │ 2017-10-02 12:59:12 │ 200 │ 5 │ 5 │
│ 10003 │ 2017-10-02 00:00:00 │ 广州 │ 32 │ 0 │ 2017-10-02 11:20:00 │ 30 │ 11 │ 11 │
│ 10004 │ 2017-10-01 00:00:00 │ 深圳 │ 35 │ 0 │ 2017-10-01 10:00:15 │ 100 │ 3 │ 3 │
│ 10004 │ 2017-10-03 00:00:00 │ 深圳 │ 35 │ 0 │ 2017-10-03 10:20:22 │ 11 │ 6 │ 6 │
└─────────┴─────────────────────┴──────┴─────┴─────┴─────────────────────┴──────┴────────────────┴────────────────┘6 rows in set. Elapsed: 0.008 sec.还可以插入几条数据来观察 tbl_agg 的结果是否符合我们定义的聚合语意
二、SimpleAggregateFunction
对于上面的案例其实在查询时依然不方便需要调用 Merge 函数本质因为 AggregateFunction 使用二进制存储。如果数据以明文存储是不是就不需要这么麻烦clickhouse 针对这类场景提供了 SimpleAggregateFunction
drop table if exists tbl_agg_s;
create table if not exists tbl_agg_s
(user_id String comment 用户id,date datetime comment 数据灌入日期时间,city String comment 用户所在城市,age Int8 comment 用户年龄,sex Int8 comment 用户性别,last_visit_date SimpleAggregateFunction(anyLast,datetime) comment 用户最后一次访问时间,cost SimpleAggregateFunction(sum, Int256) comment 用户总消费,max_dwell_time SimpleAggregateFunction(max,Int64) comment 用户最大停留时间,min_dwell_time SimpleAggregateFunction(min,Int64) comment 用户最小停留时间
) engine AggregatingMergeTree()order by (user_id, date, city, age, sex);此时该模型就可以视为完美复刻了 doris 的聚合模型因为插入和查询将变得原生化
insert into tbl_agg_s
values (10000, 2017-10-01, 北京, 20, 0, 2017-10-01 06:00:00, 20, 10, 10),(10000, 2017-10-01, 北京, 20, 0, 2017-10-01 07:00:00, 15, 2, 2),(10001, 2017-10-01, 北京, 30, 1, 2017-10-01 17:05:45, 2, 22, 22),(10002, 2017-10-02, 上海, 20, 1, 2017-10-02 12:59:12, 200, 5, 5),(10003, 2017-10-02, 广州, 32, 0, 2017-10-02 11:20:00, 30, 11, 11),(10004, 2017-10-01, 深圳, 35, 0, 2017-10-01 10:00:15, 100, 3, 3),(10004, 2017-10-03, 深圳, 35, 0, 2017-10-03 10:20:22, 11, 6, 6);select * from tbl_agg_s;从名字也可以看出相对 AggregateFunction 就不是那么通用即支持的聚合类型相对较少
anyanyLastminmaxsumsumWithOverflowgroupBitAndgroupBitOrgroupBitXorgroupArrayArraygroupUniqArrayArraysumMapminMapmaxMap
但这些其实已经够用了同时在上面的聚合场景下 SimpleAggregateFunction 会有更高的性能。 提问: 为什么没有 count