欢迎大家星标、关注
今天和大家分享一个小技巧。
不知各位在使用 AggregatingMergeTree 这个神器表引擎的时候,有没有觉得过很别扭,反正我有...
(什么?不知道AggregatingMergeTree? 赶快去看看我的书,第7章有详细说明)
AggregatingMergeTree 需要搭配 AggregateFunction 数据类型一起使用,非常强大,例如下面这张表:
CREATE TABLE ch_label_string(
labelname String,
labelvalue String,
uv AggregateFunction(groupBitmap,UInt64)
)ENGINE = AggregatingMergeTree()
ORDER BY (labelname,labelvalue)
PARTITION BY labelname
uv 字段使用了 AggregateFunction 类型,那么在这张表触发 Merge 动作的时候,就能按照指定的聚合函数进行预计算。
其实问题主要也就出在这个 AggregateFunction 数据类型上,因为该类型的字段是不能按照正常方式写入的,例如我们执行下面的语句是不行的:
INSERT INTO TABLE label_string values ('tag' ,'A' ,1)
DB::Exception: Cannot convert UInt64 to AggregateFunction(groupBitmap, UInt64): data for INSERT was parsed from query
错误提示不能把 UInt64 转到 AggregateFunction 类型。
那我们用 AggregateFunction 写入呢?
INSERT INTO TABLE label_string values ('tag' ,'A' , groupBitmapState(toUInt64(1))
DB::Exception: Cannot parse expression of type AggregateFunction(groupBitmap, UInt64) here: groupBitmapState(toUInt64(1))
;: data for INSERT was parsed from query
不好意思,没有这种语法,在INSERT VALUES 这种写法中是不能调用函数的。
那么正确的写法是什么呢?正确的写法是使用 INSERT SELECT:
INSERT INTO TABLE label_string SELECT 'tag' ,'A' , groupBitmapState(toUInt64(1))
Ok.
0 rows in set. Elapsed: 0.012 sec.
这种用法写个 Demo 还行,可以要在正式业务中写入大量数据就不灵了呀。
现在进入正题,今天和大家分享一个小技巧。
首先新建一张结果表,这是最终面向业务查询的表,使用 AggregatingMergeTree 表引擎:
CREATE TABLE ch_label_string(
labelname String,
labelvalue String,
uv AggregateFunction(groupBitmap,UInt64)
)ENGINE = AggregatingMergeTree()
ORDER BY (labelname,labelvalue)
PARTITION BY labelname
其中 uv 字段是 AggregateFunction(groupBitmap,UInt64) 类型。
接着用 Null 引擎新建一张和 ch_label_string 一样的镜像表:
CREATE TABLE ch_label_string_null(
labelname String,
labelvalue String,
uv UInt64
) Engine = Null;
在这张表中,uv 字段使用普通的 UInt64。
Null 引擎和 Unix 系统的空设备 /dev/null 很像,向它写入的数据都会被丢弃掉。(我在书的第8章同样介绍过)
接着重头戏来了,新建一张物化视图:
CREATE MATERIALIZED VIEW ch_label_string_queue TO ch_label_string AS
SELECT
labelname,
labelvalue,
groupBitmapState(uv) AS uv
FROM ch_label_string_null
GROUP BY
labelname,
labelvalue
这里使用了如下的语法:
CREATE MATERIALIZED VIEW xxx TO dest_table
这样一来,该物化视图的作用就如同数据管道一般,每当 ch_label_string_null 有数据写入,就会按照 SELECT 语句源源不断的把数据写入到 ch_label_string。
在数据写入的时候,我们直接面向 ch_label_string_null 写入,并通过物化视图,直接将数据写入到了目标的 ch_label_string 这张表。
而ch_label_string_null 由于是 Null 引擎,本身不会存储任何多余的数据。
在数据查询的时候,我们则直接面向结果表 ch_label_string。
现在我们写入数据试一试,面向 ch_label_string_null 写入:
INSERT INTO TABLE ch_label_string_null
WITH(
SELECT ['A','B','C','D','E','F','G']
)AS dict
SELECT 'tag_a',dict[number%7+1],number FROM numbers(100000)
0 rows in set. Elapsed: 0.024 sec. Processed 100.00 thousand rows, 800.00 KB (4.11 million rows/s., 32.87 MB/s.)
Null 引擎不会存储数据:
SELECT COUNT()
FROM ch_label_string_null
┌─count()─┐
│ 0 │
└─────────┘
1 rows in set. Elapsed: 0.003 sec.
现在面向 ch_label_string 查询,可以看到数据已经通过物化视图构建的管道被写入:
select * from ch_label_string;
并且 ch_label_string 已经按照 GROUP BY 条件聚合,而 uv 字段使用了二进制存储。
至此,我们就可以进行一些业务操作了,比如利用 bitmap 函数进行交集的判断:
SELECT bitmapToArray(bitmapAnd(groupBitmapMergeState(uv), bitmapBuild([toUInt64(3), toUInt64(406), toUInt64(5000000)]))) AS res
FROM ch_label_string
Query id: 27337e9f-d206-490c-8d81-0f717a8896fa
┌─res─────┐
│ [3,406] │
└─────────┘
1 rows in set. Elapsed: 0.006 sec.
好了,今天的分享就到这里吧,原创不易,如果这篇文章对你有帮助,欢迎 点赞、转发、在看 三连击
欢迎大家扫码关注我的公众号和视频号:
本文分享自 ClickHouse的秘密基地 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!