前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >利用Null引擎和物化视图构建数据管道

利用Null引擎和物化视图构建数据管道

作者头像
Nauu
发布2021-04-29 17:44:45
1.1K1
发布2021-04-29 17:44:45
举报

欢迎大家星标、关注

今天和大家分享一个小技巧。

不知各位在使用 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.

好了,今天的分享就到这里吧,原创不易,如果这篇文章对你有帮助,欢迎 点赞、转发、在看 三连击

欢迎大家扫码关注我的公众号和视频号:

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-04-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 ClickHouse的秘密基地 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档