用空间换时间是编程世界的指导思想之一。
“视图(view)”是传统关系型数据库设计中的一个基本概念,其根本目的是为了简化查询,那么在clickhouse的设计中也借鉴了这一概念。
视图分为普通和物化两种:普通视图的话只是一层简单的查询代理,其本身不会占用任何存储空间,当然也不会带来查询性能的提升;而物化视图则具有独立的存储,在原表写入数据的时候,物化视图的数据也会跟着更新,因为有预聚合的存在,导致物化视图能够在很大程度上提升聚合结果的查询效率,当然牺牲的就是一些存储空间。
clickhouse物化视图的实现很大程度上是基于AggregatingMergeTree表引擎,虽然这个表引擎本身可以独立使用,但它主要的使用场景还是用在物化视图上。
AggregatingMergeTree是MergeTree的一种形式,但其在使用方式上与其他MergeTree有很大的不同。举例:
CREATE TABLE agg_tbl(
country String,
event String,
gold_medal AggregateFunction(sum,UInt32),
date_time DateTime
) ENGINE=AggregatingMergeTree()
PARTITION BY toYYYYMMDD(date_time)
ORDER BY (country,event);
在分区合并的过程中,在每个数据分区内按照ORDER BY的主键进行聚合,而其他字段使用何种聚合函数则是通过定义AggregateFunction来实现。
AggregateFunction是clickhouse提供的一种特殊的数据类型,它以二进制的方式存储中间数据
。在写入该字段的时候调用xxxState函数,查询的时候则是调用xxxMerge函数,其中,xxx表示具体的聚合函数,比如上例中的sum。
写入举例:
INSERT INTO TABLE agg_tbl select 'china','swimming',sumState(toUInt32(2)),'2021-08-01 10:00:00'
查询的时候如果直接访问gold_medal列将会是无法显示的二进制形式,只能通过调用sumMerge函数访问。
select country,event,sumMerge(gold_medal) from agg_tbl group by country,event;
看起来确实比较繁琐,不过别担心,大部分时候我们不需要这要用,而是在新建物化视图的时候使用,下一节我们就来感受一下~~
创建物化视图的基本语法:
CREATE MATERIALIZED VIEW [ IF NOT EXISTS ] [db.]table_name [ ENGINE= engine ] [ POPULATE] AS SELECT ...
ENGINE我们一般选用上文介绍的AggregatingMergeTree; populate修饰符则决定了物化视图的初始策略:如果使用了POPULATE,那么会将源表中已存在的数据一起导入;反之,则只会同步在此之后被写入源表的数据。 物化视图不支持同步删除,意味着删除源表中的数据,物化视图中的数据不会改变。
在clickhouse中,物化视图本质上一张特殊的数据表,通过show tables
命令查看,可以看到一些.inner.
为前缀的数据表,这些表即为实际物理存储物化视图数据的表。
实际举例:首先,新建一张明细表作为底表
CREATE TABLE agg_tbl(
country String,
event String,
player String,
gold_medal UInt32,
date_time DateTime
) ENGINE=MergeTree()
PARTITION BY toYYYYMMDD(date_time)
ORDER BY country;
然后,新建一张物化视图:
CREATE MATERIALIZED VIEW agg_view
ENGINE = AggregatingMergeTree()
PARTITION BY country
ORDER BY country
AS SELECT
country,
sumState(gold_medal) as gold_medal_num
from agg_tbl
GROUP BY country;
插入时直接往底表里插入明细数据即可,查询时则可以直接查询新建的物化视图:
select country, sumMerge(gold_medal_num) from agg_view group by counry;
删除物化视图,直接调用DROP TABLE即可:DROP TABLE VIEW_NAME
。