1. 什么是物化视图

通过定义一段select查询语句,从base表进行数据查询,形成一张物化视图表。物化视图表的数据独立于base表储存。对base表进行数据的插入,更新、删除也会原子性的同步到物化视图表。进行数据查询时,Doris引擎会自动以最优方式进行查询,可能查询base表,可能查询物化视图表

2. 有了rollup,为啥还需要物化视图

我们都指导rollup主要有两个功能,第一对Aggregate表提供一种更粗粒度的聚合;第二提供一种key,提高前缀索引的命中率

但是rollup不能对Duplicate表进行聚合操作。所以就有了物化视图,物化视图能对所有表模型提供一种更粗粒度的聚合,而且支持更多的聚合函数;而且也能提供一种key,提高前缀索引的命中率

3. 创建物化视图的原则

创建物化视图的select语句,如果完全和我们进行数据查询的select语句一样,则物化视图表就不能被其它数据查询select语句使用

所以最好对创建物化视图的select语句进行抽象,能被多个数据查询的select语句命中,达到一个时间和空间的平衡

4. 物化视图的使用

4.1 创建

创建物化视图的语法:

create materialized view mv_name as 
select select_expr[, select_expr, ......]
from table_name
[group by column_name[, column_name, ......]]
[order by column_name[, column_name, ......]]
[properties ('key' = 'value', ......)]

说明如下:

  • 同一个table_name的mv_name不能重复
  • select_expr:
    • 仅支持不带表达式计算的单列,聚合列。且聚合函数的参数只能是不带表达式计算的单列
    • 所有涉及到的列,均只能出现一次
  • table_name:必须是单表,非子查询
  • order by:
    • 排序列的声明顺序必须和select_expr中列声明顺序一致。如果select_expr中包含分组列的话,则排序列必须和分组列一致
    • 如果不声明order by,则根据规则自动补充排序列。 如果物化视图是聚合类型,则所有的分组列自动补充为排序列。 如果物化视图是非聚合类型,则前36个字节自动补充为排序列,如果自动补充的排序个数小于3个,则前三个作为排序列
  • properties:支持short_keys-排序列的个数;timeout-物化视图构建的超时时间

支持的聚合函数有:

  • SUM、MIN、MAX
  • COUNT、BITMAP_UNION、HLL_UNION
    • BITMAP_UNION 的形式必须为:BITMAP_UNION(TO_BITMAP(COLUMN)),column列的类型只能是整数(如果数据是负整数,则直接忽略)(largeint也不支持);或者BITMAP_UNION(COLUMN)且base表为AGG模型
    • HLL_UNION 的形式必须为:HLL_UNION(HLL_HASH(COLUMN)),column列的类型不能是DECIMAL, 或者HLL_UNION(COLUMN)且base表为AGG模型

创建物化视图是一个异步的操作

示例:
创建base表

mysql> create table advertiser_record(
    -> click_date date, 
    -> advertiser varchar(32), 
    -> channel varchar(16), 
    -> user_id int
    -> ) distributed by hash(click_date) 
    -> properties('replication_num' = '3');
Query OK, 0 rows affected (0.35 sec)

mysql>

创建物化视图。这里base表的tablet正在被调度,所以需要等调度完,才能创建物化视图成功

mysql> create materialized view advertiser_view as 
    -> select advertiser, channel, bitmap_union(to_bitmap(user_id)) 
    -> from advertiser_record 
    -> group by advertiser, channel;
ERROR 1105 (HY000): errCode = 2, detailMessage = table [advertiser_record] is not stable. Some tablets of this table may not be healthy or are being scheduled. You need to repair the table first or stop cluster balance. See 'help admin;'.
mysql>
mysql> create materialized view advertiser_view as  select advertiser, channel, bitmap_union(to_bitmap(user_id))  from advertiser_record  group by advertiser, channel;
Query OK, 0 rows affected (1.58 sec)

mysql>

4.2 查看

查看物化视图创建的进度

mysql> show alter table materialized view from test_db;
+-------+------------------------+---------------------+---------------------+------------------------+------------------+----------+---------------+----------+------+----------+---------+
| JobId | TableName              | CreateTime          | FinishTime          | BaseIndexName          | RollupIndexName  | RollupId | TransactionId | State    | Msg  | Progress | Timeout |
+-------+------------------------+---------------------+---------------------+------------------------+------------------+----------+---------------+----------+------+----------+---------+
| 15398 | advertiser_record      | 2022-08-02 16:32:23 | 2022-08-02 16:32:53 | advertiser_record      | advertiser_view  | 15399    | 1020          | FINISHED |      | NULL     | 86400   |
+-------+------------------------+---------------------+---------------------+------------------------+------------------+----------+---------------+----------+------+----------+---------+
1 rows in set (0.02 sec)

mysql>

查看当前表都有哪些物化视图,以及他们的表结构都是什么样的

mysql> desc advertiser_record all;
+-------------------+---------------+----------------------+-------------+------+-------+---------+--------------+---------+
| IndexName         | IndexKeysType | Field                | Type        | Null | Key   | Default | Extra        | Visible |
+-------------------+---------------+----------------------+-------------+------+-------+---------+--------------+---------+
| advertiser_record | DUP_KEYS      | click_date           | DATE        | Yes  | true  | NULL    |              | true    |
|                   |               | advertiser           | VARCHAR(32) | Yes  | true  | NULL    |              | true    |
|                   |               | channel              | VARCHAR(16) | Yes  | false | NULL    | NONE         | true    |
|                   |               | user_id              | INT         | Yes  | false | NULL    | NONE         | true    |
|                   |               |                      |             |      |       |         |              |         |
| advertiser_view   | AGG_KEYS      | advertiser           | VARCHAR(32) | Yes  | true  | NULL    |              | true    |
|                   |               | channel              | VARCHAR(16) | Yes  | true  | NULL    |              | true    |
|                   |               | to_bitmap(`user_id`) | BITMAP      | No   | false |         | BITMAP_UNION | true    |
+-------------------+---------------+----------------------+-------------+------+-------+---------+--------------+---------+
8 rows in set (0.07 sec)

mysql> 

4.3 删除

mysql> drop materialized view if exists advertiser_view on advertiser_record;
Query OK, 0 rows affected (0.05 sec)

mysql> 

5. 物化视图中的聚合和查询中聚合的匹配关系

物化视图聚合查询中聚合
sumsum
minmin
maxmax
countcount
bitmap_unionbitmap_union, bitmap_union_count, count(distinct)
hll_unionhll_raw_agg, hll_union_agg, ndv, approx_count_distinct

在Doris中,count(distinct)聚合的结果和bitmap_union_count聚合的结果是完全一致的。而bitmap_union_count等于bitmap_union的结果求 count, 所以如果查询中涉及到count(distinct),则通过创建带bitmap_union聚合的物化视图可加快查询

对于物化视图的聚合函数bitmap_union和hll_union,select查询匹配到物化视图后,会将select查询的聚合函数转换成物化视图的聚合函数bitmap_union和hll_union

6. explain查看select是否使用物化视图

通过explain命令来检查当前查询是否使用了物化视图。注意要先往表中插入一条数据,不然不知道从那个表查询数据最优

mysql> insert into advertiser_record(click_date, advertiser, channel, user_id) values(date('2022-08-02'), 'car_advertiser', '小程序', 1);
Query OK, 1 row affected (2.79 sec)
{'label':'insert_f3aa0cfc2c8741bd-b567f96aff6f6629', 'status':'VISIBLE', 'txnId':'1021'}

mysql> 
mysql> explain select advertiser, channel, count(distinct user_id) 
    -> from advertiser_record 
    -> group by advertiser, channel;
+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Explain String                                                                                                                                                   |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| PLAN FRAGMENT 0                                                                                                                                                  |
|   OUTPUT EXPRS:<slot 7> `advertiser` | <slot 8> `channel` | <slot 9> bitmap_union_count(`default_cluster:test_db`.`advertiser_record`.`mv_bitmap_union_user_id`) |
|   PARTITION: UNPARTITIONED                                                                                                                                       |
|                                                                                                                                                                  |
|   VRESULT SINK                                                                                                                                                   |
......省略部分......
|   0:VOlapScanNode                                                                                                                                                |
|      TABLE: advertiser_record(advertiser_view), PREAGGREGATION: ON                                                                                               |
|      partitions=1/1, tablets=10/10, tabletList=15400,15404,15408 ...                                                                                             |
|      cardinality=0, avgRowSize=48.0, numNodes=1                                                                                                                  |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
41 rows in set (0.04 sec)

mysql>

看VOlapScanNode的TABLE部分,这里命中了advertiser_view物化视图。如果命中base表,则是TABLE: advertiser_record(advertiser_record)

7. 物化视图的局限性

  • 如果删除数据语句的条件列,在物化视图中不存在,则不能进行删除操作。如果一定要删除数据,则需要先将物化视图删除,然后方可删除数据
  • 物化视图针对Unique Key数据模型,只能改变列顺序,不能起到聚合的作用,所以在Unique Key模型上不能通过创建物化视图的方式对数据进行粗粒度聚合操作
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐