第2.8章:StarRocks表设计--物化视图

在实际的业务中,我们通常需要对数据进行对原始明细数据任意维度的分析以及固定维度聚合分析。两种场景并存的情况下,聚合模型表由于缺失部分明细数据,就无法满足用户对明细数据的分析需求。如果仅建立一个明细模型,虽然可以满足任意维度的分析需求,但对明细数据进行聚合分析时,实时分析性能不佳。若同时建立一个聚合模型和一个明细模型,虽然可以满足性能和任意维度分析,但两表之间本身无关联,需要业务方自行选择分析表,不灵活也不易用。

物化视图就是StarRocks为明细模型打造的“预计算”方案,本质上也是“空间换时间”,但实现更为灵活。

假设table11是一张销售记录明细表,存储了每个交易的交易id、销售员、售卖门店、销售时间、以及金额:

CREATE TABLE table11(

    record_id int,

    seller_id int,

    store_id int,

    sale_date date,

    sale_amt bigint

) distributed BY hash(record_id)

properties("replication_num" = "1");

明细模型表table11中会保留所有的明细数据,我们自然可以进行任意维度的分析。举个例子,如果我们需要对不同门店的销售量做分析,那么SQL写法为:

SELECT store_id, SUM(sale_amt) FROM table11 GROUP BY store_id;

这时查询需要检索全表数据,现场聚合分组得出结果。

如果我们频繁需要进行这个查询,若每次都进行全表检索现场聚合,显然是比较浪费资源和耗时的。而若我们可以像在查询聚合模型一样直接获取聚合后的数据,显然查询会加速很多,这也正是我们使用物化视图主要目的。

例如针对上面的查询,我们就可以基于table11表创建一张“以售卖门店为分组,对相同售卖门店的销售额求和”的物化视图表table11_mv1。创建语句如下:

CREATE MATERIALIZED VIEW table11_mv1 AS

SELECT store_id, SUM(sale_amt)

FROM table11

GROUP BY store_id;

在创建物化视图后,当数据进入表table11时,StarRocks相当于在一直在进行物化视图中的查询,并将查询结果的数据落盘。不同于MySQL中的视图概念,物化视图中的数据是真实存储的。

补充几个概念,我们将table1-table11这样的OLAP表称为Base表(或基表),基于Base表我们可以创建物化视图表(MVs表),物化视图的数据组织形式(分区、分桶、存储等)和Base表相同,但物化视图拥有单独的前缀索引。

本质上,物化视图可以拆分理解为“物化”+“视图”,“物化”即为数据落盘存储,以实现查询加速。而“视图”则是为了建模,比如我们就可以通过物化视图来实现一个StarRocks内部的上卷分层模型。

这样,当我们再执行这条SQL时,查询就会直接获取物化视图table11_mv1中的数据,进而快速返回结果。

为table11导入数据:

insert into table11 values(211014001,10001,13,'2021-10-14',1999),(211014002,10002,13,'2021-10-14',6999),(211015098,16573,19,'2021-10-15',3999);

进行查询:

SELECT store_id, SUM(sale_amt) FROM table11 GROUP BY store_id;

这时,我们可能会疑惑在写SQL时是否需要指定物化视图来实现加速?答案是不需要。StarRocks的物化视图对用户是隐式的,当我们查询时,并不需要感知物化视图的存在,也不必显式的指定物化视图的名称,查询优化器会根据查询条件自动判断是否可以路由到相应的物化视图并选择最佳的MVs表,然后重写查询计划进行最优查询。

我们来解析上面的查询:

EXPLAIN SELECT store_id, SUM(sale_amt) FROM table11 GROUP BY store_id;

其中PREAGGREGATION:ON,就表明查询时不需要在StarRocks存储引擎中现场聚合,查询会更快。rollup:table11_mv1,即为查询命中物化视图table11_mv1:

|0:OlapScanNode

|TABLE:table11

|PREAGGREGATION:ON

|partitions=1/1

|rollup:table11_mv1

|tabletRatio=10/10

关于这里的Rollup,我们还需要再说明一下,在StarRocks产品的早期,有一个Rollup表的概念,但其应用范围比较小,后面逐步延伸出了物化视图。物化视图作为Rollup的超集,包含了Rollup的所有功能(少部分命令目前还延续了Rollup的写法)。Rollup的概念已被逐渐弱化,所以我们不需要深究,在解析查询时,知道这里的rollup是指查询命中的物化视图名称就行。

对Base表的增量导入都会作用到所有关联的MVs表中,在Base表及其所有的MVs表均完成后,导入才算完成,数据才能被看到(否则导入整体失败,具备原子性)。StarRocks会保证Base表和MVs表之间的数据是一致的,查询Base表和查询MVs表的结果不会存在数据差异。

创建物化视图是一个异步的操作,也就是说我们提交创建任务后,若语法正确,StarRocks虽然会立刻给出反馈,但会在后台对存量的数据进行计算,直到创建成功。还以table11为例,我们再创建一个物化视图table11_mv2:

CREATE MATERIALIZED VIEW table11_mv2 AS

SELECT seller_id, SUM(sale_amt)

FROM table11

GROUP BY seller_id;

查看创建进度(starrocks为当前的数据库名):

SHOW ALTER MATERIALIZED VIEW FROM starrocks;

当对应IndexName物化视图的State为FINISHED时,即为创建完成。

查看Base表table11的物化视图表信息,语句为:

desc table11 all;

查看starrocks库下面所有的物化视图:

SHOW MATERIALIZED VIEW IN starrocks;(这里可以用IN或FROM)

删除创建完成的物化视图table11_mv2(异步,但用户感知不到):

DROP MATERIALIZED VIEW IF EXISTS starrocks.table11_mv2;

由于是异步操作,若我们需要删除创建中的物化视图,可以取消其异步的创建任务,以表table11上的物化视图table11_mv1为例,取消正在创建的任务:

CANCEL ALTER MATERIALIZED VIEW FROM starrocks.table11;

执行后再次使用上面的show语句查看,当State为CANCELLED即代表已取消。

关于物化视图的使用,当前还有一些注意事项:

1、当前物化视图只支持对单个表的聚合。目前支持的聚合函数有:COUNT、MAX、MIN、SUM、HLL_UNION和BITMAP_UNION。物化视图的聚合函数的参数仅支持单列,比如:sum(a+b)也是不支持的。

2、目前物化视图主要应用于明细模型,实现固定维度数据的预聚合。对于聚合模型,从预聚合的角度来讲没有创建物化视图的意义,但我们可以使用物化视图来实现更少数据量的扫描,或者通过物化视图调整列顺序以命中前缀索引(明细模型也适用)。

以聚合模型表table03为例,若查询中的where条件经常指向state列,那查询显然是不能命中前缀的,例如:

SELECT state ,sum(pv) FROM table03 GROUP BY state;

这时我们可以为其创建一个物化视图表table03_mv1:

mysql> CREATE MATERIALIZED VIEW table03_mv1 AS SELECT state, sum(pv) FROM table03 GROUP BY state;

该物化视图表只包含两列:state和sum(pv)。执行完成后,当我们再次执行查询时,会自动命中这个物化视图表,在前缀索引加速的同时也只需扫描极少的数据量,进而快速完成这次聚合查询。

更新模型使用物化视图的限制会更多一些,其作用仅为有限的调整前缀,通常我们也不建议使用。以table04为例,我们为其创建物化视图table04_mv1,这里注意更新模型的物化视图语句,group by后要跟所有的key列:

create materialized view table04_mv1 as select order_id, create_time from table04 group by create_time, order_id;

3、主键模型目前还不支持创建物化视图(指文章更新时的1.19.5版本)。

4、如果删除语句的条件列,在物化视图中不存在,则不能进行删除操作。如果一定要删除数据,则需要先将物化视图删除,然后方可删除数据。比如table11中,若有table11_mv1存在,那是不能正常执行下面的删除语句的:

mysql> delete from table11 where record_id=211015098;

ERROR 1064 (HY000): Unknown column 'record_id' in 'index[table11_mv1]'

5、单表上过多的物化视图会影响导入的效率。导入数据时,物化视图和Base表数据是同步更新的,如果一张表的物化视图表超过10张,则有可能导致导入速度很慢,此时就像在同时导入10张表的数据一样。

6、相同列,不同聚合函数,不能同时出现在一张物化视图中,比如:select sum(a), min(a) from table不支持。

7、同一张表不能同时创建多个物化视图,只能等待上一个物化视图创建完成(State为FlNISHED),才能创建下一个物化视图。

8、物化视图的创建语句目前不支持JOIN和WHERE,也不支持GROUP BY的 HAVING子句。

9、在对空表查询时可能无法命中物化视图(启用CBO优化器后可以,开启方式:set global enable_cbo = true;)。比如我们解析上面table11中的查询:

EXPLAIN SELECT store_id, SUM(sale_amt) FROM table11 GROUP BY store_id;

可以看到:

|0:OlapScanNode

|TABLE:table11

|PREAGGREGATION: OFF. Reason: Aggregate Operator not match: SUM <--> NONE

|partitions=0/1

|rollup: null

10、删除Base表时,所有基于Base表的物化视图会被同步删除。

你可能感兴趣的:(数据库,big,data,database,分布式,mysql)