当前位置: 首页 > news >正文

Apache Doris 入门教程32:物化视图

物化视图

物化视图是将预先计算(根据定义好的 SELECT 语句)好的数据集,存储在 Doris 中的一个特殊的表。

物化视图的出现主要是为了满足用户,既能对原始明细数据的任意维度分析,也能快速的对固定维度进行分析查询。

适用场景​

  • 分析需求覆盖明细数据查询以及固定维度查询两方面。
  • 查询仅涉及表中的很小一部分列或行。
  • 查询包含一些耗时处理操作,比如:时间很久的聚合操作等。
  • 查询需要匹配不同前缀索引。

优势​

  • 对于那些经常重复的使用相同的子查询结果的查询性能大幅提升。
  • Doris 自动维护物化视图的数据,无论是新的导入,还是删除操作都能保证 Base 表和物化视图表的数据一致性,无需任何额外的人工维护成本。
  • 查询时,会自动匹配到最优物化视图,并直接从物化视图中读取数据。

自动维护物化视图的数据会造成一些维护开销,会在后面的物化视图的局限性中展开说明。

物化视图 VS Rollup​

在没有物化视图功能之前,用户一般都是使用 Rollup 功能通过预聚合方式提升查询效率的。但是 Rollup 具有一定的局限性,他不能基于明细模型做预聚合。

物化视图则在覆盖了 Rollup 的功能的同时,还能支持更丰富的聚合函数。所以物化视图其实是 Rollup 的一个超集。

也就是说,之前 ALTER TABLE ADD ROLLUP 语法支持的功能现在均可以通过 CREATE MATERIALIZED VIEW 实现。

使用物化视图​

Doris 系统提供了一整套对物化视图的 DDL 语法,包括创建,查看,删除。DDL 的语法和 PostgreSQL, Oracle 都是一致的。

创建物化视图​

这里首先你要根据你的查询语句的特点来决定创建一个什么样的物化视图。这里并不是说你的物化视图定义和你的某个查询语句一模一样就最好。这里有两个原则:

  1. 从查询语句中抽象出,多个查询共有的分组和聚合方式作为物化视图的定义。
  2. 不需要给所有维度组合都创建物化视图。

首先第一个点,一个物化视图如果抽象出来,并且多个查询都可以匹配到这张物化视图。这种物化视图效果最好。因为物化视图的维护本身也需要消耗资源。

如果物化视图只和某个特殊的查询很贴合,而其他查询均用不到这个物化视图。则会导致这张物化视图的性价比不高,既占用了集群的存储资源,还不能为更多的查询服务。

所以用户需要结合自己的查询语句,以及数据维度信息去抽象出一些物化视图的定义。

第二点就是,在实际的分析查询中,并不会覆盖到所有的维度分析。所以给常用的维度组合创建物化视图即可,从而到达一个空间和时间上的平衡。

创建物化视图是一个异步的操作,也就是说用户成功提交创建任务后,Doris 会在后台对存量的数据进行计算,直到创建成功。

具体的语法可查看CREATE MATERIALIZED VIEW 。

SinceVersion 2.0.0

Doris 2.0版本中我们对物化视图的做了一些增强(在本文的最佳实践4中有具体描述)。我们建议用户在正式的生产环境中使用物化视图前,先在测试环境中确认是预期中的查询能否命中想要创建的物化视图。

如果不清楚如何验证一个查询是否命中物化视图,可以阅读本文的最佳实践1

与此同时,我们不建议用户在同一张表上建多个形态类似的物化视图,这可能会导致多个物化视图之间的冲突使得查询命中失败(在新优化器中这个问题会有所改善)。建议用户先在测试环境中验证物化视图和查询是否满足需求并能正常使用。

支持聚合函数​

目前物化视图创建语句支持的聚合函数有:

  • SUM, MIN, MAX (Version 0.12)
  • COUNT, BITMAP_UNION, HLL_UNION (Version 0.13)

更新策略​

为保证物化视图表和 Base 表的数据一致性, Doris 会将导入,删除等对 Base 表的操作都同步到物化视图表中。并且通过增量更新的方式来提升更新效率。通过事务方式来保证原子性。

比如如果用户通过 INSERT 命令插入数据到 Base 表中,则这条数据会同步插入到物化视图中。当 Base 表和物化视图表均写入成功后,INSERT 命令才会成功返回。

查询自动匹配​

物化视图创建成功后,用户的查询不需要发生任何改变,也就是还是查询的 Base 表。Doris 会根据当前查询的语句去自动选择一个最优的物化视图,从物化视图中读取数据并计算。

用户可以通过 EXPLAIN 命令来检查当前查询是否使用了物化视图。

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

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

其中 bitmap 和 hll 的聚合函数在查询匹配到物化视图后,查询的聚合算子会根据物化视图的表结构进行改写。详细见实例2。

查询物化视图​

查看当前表都有哪些物化视图,以及他们的表结构都是什么样的。通过下面命令:

MySQL [test]> desc mv_test all;
+-----------+---------------+-----------------+----------+------+-------+---------+--------------+
| IndexName | IndexKeysType | Field           | Type     | Null | Key   | Default | Extra        |
+-----------+---------------+-----------------+----------+------+-------+---------+--------------+
| mv_test   | DUP_KEYS      | k1              | INT      | Yes  | true  | NULL    |              |
|           |               | k2              | BIGINT   | Yes  | true  | NULL    |              |
|           |               | k3              | LARGEINT | Yes  | true  | NULL    |              |
|           |               | k4              | SMALLINT | Yes  | false | NULL    | NONE         |
|           |               |                 |          |      |       |         |              |
| mv_2      | AGG_KEYS      | k2              | BIGINT   | Yes  | true  | NULL    |              |
|           |               | k4              | SMALLINT | Yes  | false | NULL    | MIN          |
|           |               | k1              | INT      | Yes  | false | NULL    | MAX          |
|           |               |                 |          |      |       |         |              |
| mv_3      | AGG_KEYS      | k1              | INT      | Yes  | true  | NULL    |              |
|           |               | to_bitmap(`k2`) | BITMAP   | No   | false |         | BITMAP_UNION |
|           |               |                 |          |      |       |         |              |
| mv_1      | AGG_KEYS      | k4              | SMALLINT | Yes  | true  | NULL    |              |
|           |               | k1              | BIGINT   | Yes  | false | NULL    | SUM          |
|           |               | k3              | LARGEINT | Yes  | false | NULL    | SUM          |
|           |               | k2              | BIGINT   | Yes  | false | NULL    | MIN          |
+-----------+---------------+-----------------+----------+------+-------+---------+--------------+

可以看到当前 mv_test 表一共有三张物化视图:mv_1, mv_2 和 mv_3,以及他们的表结构。

删除物化视图​

如果用户不再需要物化视图,则可以通过命令删除物化视图。

具体的语法可查看DROP MATERIALIZED VIEW

查看已创建的物化视图​

用户可以通过命令查看已创建的物化视图的

具体的语法可查看SHOW CREATE MATERIALIZED VIEW

取消创建物化视图​

 CANCEL ALTER TABLE MATERIALIZED VIEW FROM db_name.table_name

最佳实践1​

使用物化视图一般分为以下几个步骤:

  1. 创建物化视图
  2. 异步检查物化视图是否构建完成
  3. 查询并自动匹配物化视图

首先是第一步:创建物化视图

假设用户有一张销售记录明细表,存储了每个交易的交易 id,销售员,售卖门店,销售时间,以及金额。建表语句和插入数据语句为:

create table sales_records(record_id int, seller_id int, store_id int, sale_date date, sale_amt bigint) distributed by hash(record_id) properties("replication_num" = "1");
insert into sales_records values(1,1,1,"2020-02-02",1);

这张 sales_records 的表结构如下:

MySQL [test]> desc sales_records;
+-----------+--------+------+-------+---------+-------+
| Field     | Type   | Null | Key   | Default | Extra |
+-----------+--------+------+-------+---------+-------+
| record_id | INT    | Yes  | true  | NULL    |       |
| seller_id | INT    | Yes  | true  | NULL    |       |
| store_id  | INT    | Yes  | true  | NULL    |       |
| sale_date | DATE   | Yes  | false | NULL    | NONE  |
| sale_amt  | BIGINT | Yes  | false | NULL    | NONE  |
+-----------+--------+------+-------+---------+-------+

这时候如果用户经常对不同门店的销售量进行一个分析查询,则可以给这个 sales_records 表创建一张以售卖门店分组,对相同售卖门店的销售额求和的一个物化视图。创建语句如下:

MySQL [test]> create materialized view store_amt as select store_id, sum(sale_amt) from sales_records group by store_id;

后端返回下图,则说明创建物化视图任务提交成功。

Query OK, 0 rows affected (0.012 sec)

第二步:检查物化视图是否构建完成

由于创建物化视图是一个异步的操作,用户在提交完创建物化视图任务后,需要异步的通过命令检查物化视图是否构建完成。命令如下:

SHOW ALTER TABLE ROLLUP FROM db_name; (Version 0.12)
SHOW ALTER TABLE MATERIALIZED VIEW FROM db_name; (Version 0.13)

这个命令中 db_name 是一个参数, 你需要替换成自己真实的 db 名称。命令的结果是显示这个 db 的所有创建物化视图的任务。结果如下:

+-------+---------------+---------------------+---------------------+---------------+-----------------+----------+---------------+-----------+-------------------------------------------------------------------------------------------------------------------------+----------+---------+
| JobId | TableName     | CreateTime          | FinishedTime        | BaseIndexName | RollupIndexName | RollupId | TransactionId | State     | Msg                                                                                                                     | Progress | Timeout |
+-------+---------------+---------------------+---------------------+---------------+-----------------+----------+---------------+-----------+-------------------------------------------------------------------------------------------------------------------------+----------+---------+
| 22036 | sales_records | 2020-07-30 20:04:28 | 2020-07-30 20:04:57 | sales_records | store_amt       | 22037    | 5008          | FINISHED  |                                                                                                                         | NULL     | 86400   |
+-------+---------------+---------------------+---------------------+---------------+-----------------+----------+---------------+-----------+-------------------------------------------------------------------------------------------------------------------------+----------+---------+

其中 TableName 指的是物化视图的数据来自于哪个表,RollupIndexName 指的是物化视图的名称叫什么。其中比较重要的指标是 State。

当创建物化视图任务的 State 已经变成 FINISHED 后,就说明这个物化视图已经创建成功了。这就意味着,查询的时候有可能自动匹配到这张物化视图了。

第三步:查询

当创建完成物化视图后,用户再查询不同门店的销售量时,就会直接从刚才创建的物化视图 store_amt 中读取聚合好的数据。达到提升查询效率的效果。

用户的查询依旧指定查询 sales_records 表,比如:

SELECT store_id, sum(sale_amt) FROM sales_records GROUP BY store_id;

上面查询就能自动匹配到 store_amt。用户可以通过下面命令,检验当前查询是否匹配到了合适的物化视图。

EXPLAIN SELECT store_id, sum(sale_amt) FROM sales_records GROUP BY store_id;
+----------------------------------------------------------------------------------------------+
| Explain String                                                                               |
+----------------------------------------------------------------------------------------------+
| PLAN FRAGMENT 0                                                                              |
|   OUTPUT EXPRS:                                                                              |
|     <slot 4> `default_cluster:test`.`sales_records`.`mv_store_id`                            |
|     <slot 5> sum(`default_cluster:test`.`sales_records`.`mva_SUM__`sale_amt``)               |
|   PARTITION: UNPARTITIONED                                                                   |
|                                                                                              |
|   VRESULT SINK                                                                               |
|                                                                                              |
|   4:VEXCHANGE                                                                                |
|      offset: 0                                                                               |
|                                                                                              |
| PLAN FRAGMENT 1                                                                              |
|                                                                                              |
|   PARTITION: HASH_PARTITIONED: <slot 4> `default_cluster:test`.`sales_records`.`mv_store_id` |
|                                                                                              |
|   STREAM DATA SINK                                                                           |
|     EXCHANGE ID: 04                                                                          |
|     UNPARTITIONED                                                                            |
|                                                                                              |
|   3:VAGGREGATE (merge finalize)                                                              |
|   |  output: sum(<slot 5> sum(`default_cluster:test`.`sales_records`.`mva_SUM__`sale_amt``)) |
|   |  group by: <slot 4> `default_cluster:test`.`sales_records`.`mv_store_id`                 |
|   |  cardinality=-1                                                                          |
|   |                                                                                          |
|   2:VEXCHANGE                                                                                |
|      offset: 0                                                                               |
|                                                                                              |
| PLAN FRAGMENT 2                                                                              |
|                                                                                              |
|   PARTITION: HASH_PARTITIONED: `default_cluster:test`.`sales_records`.`record_id`            |
|                                                                                              |
|   STREAM DATA SINK                                                                           |
|     EXCHANGE ID: 02                                                                          |
|     HASH_PARTITIONED: <slot 4> `default_cluster:test`.`sales_records`.`mv_store_id`          |
|                                                                                              |
|   1:VAGGREGATE (update serialize)                                                            |
|   |  STREAMING                                                                               |
|   |  output: sum(`default_cluster:test`.`sales_records`.`mva_SUM__`sale_amt``)               |
|   |  group by: `default_cluster:test`.`sales_records`.`mv_store_id`                          |
|   |  cardinality=-1                                                                          |
|   |                                                                                          |
|   0:VOlapScanNode                                                                            |
|      TABLE: default_cluster:test.sales_records(store_amt), PREAGGREGATION: ON                |
|      partitions=1/1, tablets=10/10, tabletList=50028,50030,50032 ...                         |
|      cardinality=1, avgRowSize=1520.0, numNodes=1                                            |
+----------------------------------------------------------------------------------------------+

从最底部的test.sales_records(store_amt)可以表明这个查询命中了store_amt这个物化视图。值得注意的是,如果表中没有数据,那么可能不会命中物化视图。

最佳实践2 PV,UV​

业务场景: 计算广告的 UV,PV。

假设用户的原始广告点击数据存储在 Doris,那么针对广告 PV, UV 查询就可以通过创建 bitmap_union 的物化视图来提升查询速度。

通过下面语句首先创建一个存储广告点击数据明细的表,包含每条点击的点击时间,点击的是什么广告,通过什么渠道点击,以及点击的用户是谁。

create table advertiser_view_record(time date, advertiser varchar(10), channel varchar(10), user_id int) distributed by hash(time) properties("replication_num" = "1");
insert into advertiser_view_record values("2020-02-02",'a','a',1);

原始的广告点击数据表结构为:

MySQL [test]> desc advertiser_view_record;
+------------+-------------+------+-------+---------+-------+
| Field      | Type        | Null | Key   | Default | Extra |
+------------+-------------+------+-------+---------+-------+
| time       | DATE        | Yes  | true  | NULL    |       |
| advertiser | VARCHAR(10) | Yes  | true  | NULL    |       |
| channel    | VARCHAR(10) | Yes  | false | NULL    | NONE  |
| user_id    | INT         | Yes  | false | NULL    | NONE  |
+------------+-------------+------+-------+---------+-------+
4 rows in set (0.001 sec)

  1. 创建物化视图

    由于用户想要查询的是广告的 UV 值,也就是需要对相同广告的用户进行一个精确去重,则查询一般为:

    SELECT advertiser, channel, count(distinct user_id) FROM advertiser_view_record GROUP BY advertiser, channel;
    

    针对这种求 UV 的场景,我们就可以创建一个带 bitmap_union 的物化视图从而达到一个预先精确去重的效果。

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

    针对这个 Case,则可以创建一个根据广告和渠道分组,对 user_id 进行精确去重的物化视图。

    MySQL [test]> create materialized view advertiser_uv as select advertiser, channel, bitmap_union(to_bitmap(user_id)) from advertiser_view_record group by advertiser, channel;
    Query OK, 0 rows affected (0.012 sec)
    

    注意:因为本身 user_id 是一个 INT 类型,所以在 Doris 中需要先将字段通过函数 to_bitmap 转换为 bitmap 类型然后才可以进行 bitmap_union 聚合。

    创建完成后, 广告点击明细表和物化视图表的表结构如下:

    MySQL [test]> desc advertiser_view_record all;
    +------------------------+---------------+----------------------+-------------+------+-------+---------+--------------+
    | IndexName              | IndexKeysType | Field                | Type        | Null | Key   | Default | Extra        |
    +------------------------+---------------+----------------------+-------------+------+-------+---------+--------------+
    | advertiser_view_record | DUP_KEYS      | time                 | DATE        | Yes  | true  | NULL    |              |
    |                        |               | advertiser           | VARCHAR(10) | Yes  | true  | NULL    |              |
    |                        |               | channel              | VARCHAR(10) | Yes  | false | NULL    | NONE         |
    |                        |               | user_id              | INT         | Yes  | false | NULL    | NONE         |
    |                        |               |                      |             |      |       |         |              |
    | advertiser_uv          | AGG_KEYS      | advertiser           | VARCHAR(10) | Yes  | true  | NULL    |              |
    |                        |               | channel              | VARCHAR(10) | Yes  | true  | NULL    |              |
    |                        |               | to_bitmap(`user_id`) | BITMAP      | No   | false |         | BITMAP_UNION |
    +------------------------+---------------+----------------------+-------------+------+-------+---------+--------------+
    

  2. 查询自动匹配

    当物化视图表创建完成后,查询广告 UV 时,Doris 就会自动从刚才创建好的物化视图 advertiser_uv 中查询数据。比如原始的查询语句如下:

    SELECT advertiser, channel, count(distinct user_id) FROM advertiser_view_record GROUP BY advertiser, channel;
    

    在选中物化视图后,实际的查询会转化为:

    SELECT advertiser, channel, bitmap_union_count(to_bitmap(user_id)) FROM advertiser_uv GROUP BY advertiser, channel;
    

    通过 EXPLAIN 命令可以检验到 Doris 是否匹配到了物化视图:

    mysql [test]>explain SELECT advertiser, channel, count(distinct user_id) FROM  advertiser_view_record GROUP BY advertiser, channel;
    +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | Explain String                                                                                                                                                                 |
    +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | PLAN FRAGMENT 0                                                                                                                                                                |
    |   OUTPUT EXPRS:                                                                                                                                                                |
    |     <slot 9> `default_cluster:test`.`advertiser_view_record`.`mv_advertiser`                                                                                                   |
    |     <slot 10> `default_cluster:test`.`advertiser_view_record`.`mv_channel`                                                                                                     |
    |     <slot 11> bitmap_union_count(`default_cluster:test`.`advertiser_view_record`.`mva_BITMAP_UNION__to_bitmap_with_check(`user_id`)`)                                          |
    |   PARTITION: UNPARTITIONED                                                                                                                                                     |
    |                                                                                                                                                                                |
    |   VRESULT SINK                                                                                                                                                                 |
    |                                                                                                                                                                                |
    |   4:VEXCHANGE                                                                                                                                                                  |
    |      offset: 0                                                                                                                                                                 |
    |                                                                                                                                                                                |
    | PLAN FRAGMENT 1                                                                                                                                                                |
    |                                                                                                                                                                                |
    |   PARTITION: HASH_PARTITIONED: <slot 6> `default_cluster:test`.`advertiser_view_record`.`mv_advertiser`, <slot 7> `default_cluster:test`.`advertiser_view_record`.`mv_channel` |
    |                                                                                                                                                                                |
    |   STREAM DATA SINK                                                                                                                                                             |
    |     EXCHANGE ID: 04                                                                                                                                                            |
    |     UNPARTITIONED                                                                                                                                                              |
    |                                                                                                                                                                                |
    |   3:VAGGREGATE (merge finalize)                                                                                                                                                |
    |   |  output: bitmap_union_count(<slot 8> bitmap_union_count(`default_cluster:test`.`advertiser_view_record`.`mva_BITMAP_UNION__to_bitmap_with_check(`user_id`)`))              |
    |   |  group by: <slot 6> `default_cluster:test`.`advertiser_view_record`.`mv_advertiser`, <slot 7> `default_cluster:test`.`advertiser_view_record`.`mv_channel`                 |
    |   |  cardinality=-1                                                                                                                                                            |
    |   |                                                                                                                                                                            |
    |   2:VEXCHANGE                                                                                                                                                                  |
    |      offset: 0                                                                                                                                                                 |
    |                                                                                                                                                                                |
    | PLAN FRAGMENT 2                                                                                                                                                                |
    |                                                                                                                                                                                |
    |   PARTITION: HASH_PARTITIONED: `default_cluster:test`.`advertiser_view_record`.`time`                                                                                          |
    |                                                                                                                                                                                |
    |   STREAM DATA SINK                                                                                                                                                             |
    |     EXCHANGE ID: 02                                                                                                                                                            |
    |     HASH_PARTITIONED: <slot 6> `default_cluster:test`.`advertiser_view_record`.`mv_advertiser`, <slot 7> `default_cluster:test`.`advertiser_view_record`.`mv_channel`          |
    |                                                                                                                                                                                |
    |   1:VAGGREGATE (update serialize)                                                                                                                                              |
    |   |  STREAMING                                                                                                                                                                 |
    |   |  output: bitmap_union_count(`default_cluster:test`.`advertiser_view_record`.`mva_BITMAP_UNION__to_bitmap_with_check(`user_id`)`)                                           |
    |   |  group by: `default_cluster:test`.`advertiser_view_record`.`mv_advertiser`, `default_cluster:test`.`advertiser_view_record`.`mv_channel`                                   |
    |   |  cardinality=-1                                                                                                                                                            |
    |   |                                                                                                                                                                            |
    |   0:VOlapScanNode                                                                                                                                                              |
    |      TABLE: default_cluster:test.advertiser_view_record(advertiser_uv), PREAGGREGATION: ON                                                                                     |
    |      partitions=1/1, tablets=10/10, tabletList=50075,50077,50079 ...                                                                                                           |
    |      cardinality=0, avgRowSize=48.0, numNodes=1                                                                                                                                |
    +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    

    在 EXPLAIN 的结果中,首先可以看到 VOlapScanNode 命中了 advertiser_uv。也就是说,查询会直接扫描物化视图的数据。说明匹配成功。

    其次对于 user_id 字段求 count(distinct) 被改写为求 bitmap_union_count(to_bitmap)。也就是通过 Bitmap 的方式来达到精确去重的效果。

最佳实践3​

业务场景:匹配更丰富的前缀索引

用户的原始表有 (k1, k2, k3) 三列。其中 k1, k2 为前缀索引列。这时候如果用户查询条件中包含 where k1=1 and k2=2 就能通过索引加速查询。

但是有些情况下,用户的过滤条件无法匹配到前缀索引,比如 where k3=3。则无法通过索引提升查询速度。

创建以 k3 作为第一列的物化视图就可以解决这个问题。

  1. 创建物化视图

    CREATE MATERIALIZED VIEW mv_1 as SELECT k3, k2, k1 FROM tableA ORDER BY k3;
    

    通过上面语法创建完成后,物化视图中既保留了完整的明细数据,且物化视图的前缀索引为 k3 列。表结构如下:

    MySQL [test]> desc tableA all;
    +-----------+---------------+-------+------+------+-------+---------+-------+
    | IndexName | IndexKeysType | Field | Type | Null | Key   | Default | Extra |
    +-----------+---------------+-------+------+------+-------+---------+-------+
    | tableA    | DUP_KEYS      | k1    | INT  | Yes  | true  | NULL    |       |
    |           |               | k2    | INT  | Yes  | true  | NULL    |       |
    |           |               | k3    | INT  | Yes  | true  | NULL    |       |
    |           |               |       |      |      |       |         |       |
    | mv_1      | DUP_KEYS      | k3    | INT  | Yes  | true  | NULL    |       |
    |           |               | k2    | INT  | Yes  | false | NULL    | NONE  |
    |           |               | k1    | INT  | Yes  | false | NULL    | NONE  |
    +-----------+---------------+-------+------+------+-------+---------+-------+
    

  2. 查询匹配

    这时候如果用户的查询存在 k3 列的过滤条件是,比如:

    select k1, k2, k3 from table A where k3=3;
    

    这时候查询就会直接从刚才创建的 mv_1 物化视图中读取数据。物化视图对 k3 是存在前缀索引的,查询效率也会提升。

最佳实践4​

SinceVersion 2.0.0

Doris 2.0中,我们对物化视图所支持的表达式做了一些增强,本示例将主要体现新版本物化视图对各种表达式的支持和提前过滤。

  1. 创建一个 Base 表并插入一些数据。
create table d_table (k1 int null,k2 int not null,k3 bigint null,k4 date null
)
duplicate key (k1,k2,k3)
distributed BY hash(k1) buckets 3
properties("replication_num" = "1");insert into d_table select 1,1,1,'2020-02-20';
insert into d_table select 2,2,2,'2021-02-20';
insert into d_table select 3,-3,null,'2022-02-20';

  1. 创建一些物化视图。
create materialized view k1a2p2ap3ps as select abs(k1)+k2+1,sum(abs(k2+2)+k3+3) from d_table group by abs(k1)+k2+1;
create materialized view kymd as select year(k4),month(k4) from d_table where year(k4) = 2020; // 提前用where表达式过滤以减少物化视图中的数据量。

  1. 用一些查询测试是否成功命中物化视图。
select abs(k1)+k2+1,sum(abs(k2+2)+k3+3) from d_table group by abs(k1)+k2+1; // 命中k1a2p2ap3ps
select bin(abs(k1)+k2+1),sum(abs(k2+2)+k3+3) from d_table group by bin(abs(k1)+k2+1); // 命中k1a2p2ap3ps
select year(k4),month(k4) from d_table; // 无法命中物化视图,因为where条件不匹配
select year(k4)+month(k4) from d_table where year(k4) = 2020; // 命中kymd

局限性​

  1. 如果删除语句的条件列,在物化视图中不存在,则不能进行删除操作。如果一定要删除数据,则需要先将物化视图删除,然后方可删除数据。
  2. 单表上过多的物化视图会影响导入的效率:导入数据时,物化视图和 Base 表数据是同步更新的,如果一张表的物化视图表超过 10 张,则有可能导致导入速度很慢。这就像单次导入需要同时导入 10 张表数据是一样的。
  3. 物化视图针对 Unique Key数据模型,只能改变列顺序,不能起到聚合的作用,所以在Unique Key模型上不能通过创建物化视图的方式对数据进行粗粒度聚合操作
  4. 目前一些优化器对sql的改写行为可能会导致物化视图无法被命中,例如k1+1-1被改写成k1,between被改写成<=和>=,day被改写成dayofmonth,遇到这种情况需要手动调整下查询和物化视图的语句。

异常错误​

  1. DATA_QUALITY_ERROR: "The data quality does not satisfy, please check your data" 由于数据质量问题或者 Schema Change 内存使用超出限制导致物化视图创建失败。如果是内存问题,调大memory_limitation_per_thread_for_schema_change_bytes参数即可。 注意:to_bitmap 的参数仅支持正整型, 如果原始数据中存在负数,会导致物化视图创建失败。String 类型的字段可使用 bitmap_hash 或 bitmap_hash64 计算 Hash 值,并返回 Hash 值的 bitmap。

更多帮助​

关于物化视图使用的更多详细语法及最佳实践,请参阅 CREATE MATERIALIZED VIEW 和 DROP MATERIALIZED VIEW 命令手册,你也可以在 MySQL 客户端命令行下输入 HELP CREATE MATERIALIZED VIEW 和HELP DROP MATERIALIZED VIEW 获取更多帮助信息。

相关文章:

Apache Doris 入门教程32:物化视图

物化视图 物化视图是将预先计算&#xff08;根据定义好的 SELECT 语句&#xff09;好的数据集&#xff0c;存储在 Doris 中的一个特殊的表。 物化视图的出现主要是为了满足用户&#xff0c;既能对原始明细数据的任意维度分析&#xff0c;也能快速的对固定维度进行分析查询。 …...

PHP substr()函数详解,PHP截取字符串。

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 substr 一、截取字符串二、截取中文字符串三、leng…...

关于flink-sql-connector-phoenix的重写逻辑

目录 重写意义 代码结构 调用链路 POM文件配置 代码解析 一、PhoenixJdbcDynamicTableFactory...

Django进阶:DRF(Django REST framework)

什么是DRF&#xff1f; DRF即Django REST framework的缩写&#xff0c;官网上说&#xff1a;Django REST framework是一个强大而灵活的工具包&#xff0c;用于构建Web API。 简单来说&#xff1a;通过DRF创建API后&#xff0c;就可以通过HTTP请求来获取、创建、更新或删除数据(…...

Flink CDC系列之:Oracle CDC 导入 Elasticsearch

Flink CDC系列之&#xff1a;Oracle CDC 导入 Elasticsearch 一、深入理解Flink Oracle CDC Connector二、创建docker-compose.yml文件三、启动容器四、下载Flink Oracle CDC的jar包五、启动 Flink 集群&#xff0c;再启动 SQL CLI六、检查 ElasticSearch 中的结果七、在 Oracl…...

Linux忘记root密码解决方法

当我们忘记root密码进不去服务器怎么办&#xff1f;不要担心&#xff0c;可以进入到linux的救援模式修改root密码。 下面直接上干货&#xff0c;流程如下&#xff1a; 1.重启电脑&#xff0c;按上下键滑动&#xff0c;保证不进入开机流程&#xff0c;然后按e键 2.出现此页面…...

AR/VR眼镜转接器方案,实现同时传输视频快充方案

简介 虚拟现实头戴显示器设备&#xff0c;简称VR头显VR眼镜&#xff0c;是利用仿真技术与计算机图形学人机接口技术多媒体技术传感技术网络技术等多种技术集合的产品&#xff0c;是借助计算机及最新传感器技术创造的一种崭新的人机交互手段。VR头显VR眼镜是一个跨时代的产品。不…...

ASP.NET Core中路由规则匹配

RESTful约束&#xff0c;如果在一个控制器里面有多个Get、Post...的操作 1、在一个控制器里面可以定义多个API方法 2、通过路由规则来区分 /// <summary> /// 获取用户信息 /// </summary> /// <param name"user"></param> /// <returns…...

IDEA:Error running,Command line is too long. 解决方法

报错如下&#xff1a; Error running SendSmsUtil. Command line is too long. Shorten the command line via JAR manifest or via a classpath file and rerun.原因是启动命令过长。 解决方法&#xff1a; 1、打开Edit Configurations 2、点击Modify options设置&#x…...

什么是反射机制?为什么反射慢?

目录 面试回答 知识扩展 反射常见的使用方式 反射和 Class 的关系 面试回答 反射指的是程序在运行时能够获取自身的信息。在 java 中&#xff0c;只要给定类的名字&#xff0c;那么就可以通过反射机制来获得类的所有属性和方法。 Java 的反射可以&#xff1a; 在运行时判断…...

list元素

列表元素 列表元素分为有序列表和无序列表 有序列表 ol – order list – 有序列表 li – list item – 列表元素 <ol type"1"><li>有序列表1</li><li>有序列表2</li><li>有序列表3</li> </ol>属性 type type属…...

OkHttp 源码浅析一

演进之路:原生Android框架不好用 ---- HttpUrlConnect 和 Apache HTTPClient 第一版 底层使用HTTPURLConnect 第二版 Square构建 从Android4.4开始 基本使用: val okhttp OkHttpClient()val request Request.Builder().url("http://www.baidu.com").buil…...

【解决问题】远程仓库GitHub/GitLab添加了SSH Key之后依然无法clone的解决办法

GitHub/GitLab添加了SSH Key之后依然无法clone的解决办法 问题现象解决办法 问题现象 在Git远程仓库添加了自己的ssh key到账户下&#xff0c;git clone时&#xff0c;依然报错clone失败&#xff0c;请检查是否没有权限进行clone操作。 解决办法 在git的安装目录下&#xff…...

回归预测 | MATLAB实现SA-SVM模拟退火算法优化支持向量机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现SA-SVM模拟退火算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现SA-SVM模拟退火算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效果一览基本…...

Spring事务和事务传播机制(1)

前言&#x1f36d; ❤️❤️❤️SSM专栏更新中&#xff0c;各位大佬觉得写得不错&#xff0c;支持一下&#xff0c;感谢了&#xff01;❤️❤️❤️ Spring Spring MVC MyBatis_冷兮雪的博客-CSDN博客 在Spring框架中&#xff0c;事务管理是一种用于维护数据库操作的一致性和…...

如何快速在vscode中实现不同python文件的对比查看

总体而言&#xff1a;两种方式。一种是直接点击vscode右上角的图标&#xff08;见下图&#xff09;。 另一种方式就是使用快捷键啦“**Ctrl**”&#xff0c;用的时候选中想要对比的python文件&#xff0c;然后快捷键就可以达到下图效果了&#xff1a; 建议大家直接使用第二种…...

网络安全---Ring3下动态链接库.so函数劫持

一、动态链接库劫持原理 1.1、原理 Unix操作系统中&#xff0c;程序运行时会按照一定的规则顺序去查找依赖的动态链接库&#xff0c;当查找到指定的so文件时&#xff0c;动态链接器(/lib/ld-linux.so.X)会将程序所依赖的共享对象进行装载和初始化&#xff0c;而为什么可以使用…...

leetcode283. 移动零

难度&#xff1a;简单题 题目 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 思路&#xff1a; 一开始想&#xff0c;从前往后遍历&am…...

GuLi商城-前端基础Vue-生命周期和钩子函数

下图展示了实例的生命周期。你不需要立马弄明白所有的东西&#xff0c;不过随着你的不断学习和使用&#xff0c;它 的参考价值会越来越高。 VUE 的生命周期指的是组件在创建、运行和销毁过程中所经历的一系列事件&#xff0c;通过这些事件可以 让开发者在不同阶段进行相应的…...

输入输出+暴力模拟入门:魔法之树、染色の树、矩阵、字母加密、玫瑰鸭

秋招实习刷题网站推荐&#xff1a;codefun2000.com&#xff0c;还有题解博客&#xff1a;blog.codefun2000.com/。以下内容都是来自塔子哥的~ 输入输出 2023.04.15-春招-第三题-魔法之树 //#include<bits/stdc.h> #include<vector> #include<iostream>usin…...

​Kubernetes的演变:从etcd到分布式SQL的过渡

DevRel领域专家Denis Magda表示&#xff0c;他偶然发现了一篇解释如何用PostgreSQL无缝替换etcd的文章。该文章指出&#xff0c;Kine项目作为外部etcd端点&#xff0c;可以将Kubernetes etcd请求转换为底层关系数据库的SQL查询。 受到这种方法的启发&#xff0c;Magda决定进一步…...

29、简单通过git把项目远程提交到gitee

简单通过git把项目远程提交到gitee 1、在gitee上创建一个仓库 2、在要提交的项目文件夹打开git 输入 git init 初始化git 然后设置下用户名和邮箱 git config --global user.name “username” git config --global user.email “yourEmail” 因为我是要把文件简单提交到…...

元宇宙之应用(04)沉浸式游戏

在数字科技迅猛发展的今天&#xff0c;元宇宙的概念正逐渐从科幻走向现实&#xff0c;重新定义了人们与虚拟世界的交互方式。在这一概念的引领下&#xff0c;"沉浸式游戏" 蓬勃发展&#xff0c;为游戏体验带来了前所未有的深度和广度。那么&#xff0c;为什么沉浸式游…...

浙大数据结构第八周之08-图7 公路村村通

题目详情&#xff1a; 现有村落间道路的统计数据表中&#xff0c;列出了有可能建设成标准公路的若干条道路的成本&#xff0c;求使每个村落都有公路连通所需要的最低成本。 输入格式: 输入数据包括城镇数目正整数N&#xff08;≤1000&#xff09;和候选道路数目M&#xff08…...

SpringBoot 解决跨域问题

同源策略&#xff08;CORS&#xff09;&#xff1a;浏览器在解析发送的请求时&#xff0c;要求浏览器的路径与发送的请求的路径必须满足三个要求&#xff0c;即请求的协议、域名、端口号都相同&#xff0c;满足同源策略&#xff0c;才可以访问服务器&#xff0c;否则&#xff0…...

2023 年牛客多校第十场题解

C Multiplication 题意&#xff1a;定义 k k k-shift 数是满足 k x y ‾ y x ‾ k\overline{xy}\overline{yx} kxy​yx​ 的数字。给定 k k k&#xff0c;求最大不超过 n n n 的 k k k-shift 数。 1 ≤ n ≤ 1 0 100 1 \le n \le 10^{100} 1≤n≤10100&#xff0c; 2 ≤…...

韦东山老师 RTOS 入门课程(一)RTOS 介绍,熟悉裸机的汇编逻辑

韦东山老师 RTOS 入门课程 课程链接&#xff1a;韦东山直播公开课&#xff1a;RTOS实战项目之实现多任务系统 第1节&#xff1a;裸机程序框架和缺陷_哔哩哔哩_bilibili RTOS 介绍 裸机&#xff1a;固定顺序执行。 中断&#xff1a;可以一直专心做循环里的事情&#xff0c;直…...

WebRTC | SDP详解

目录 一、SDP标准规范 1. SDP结构 2. SDP内容及type类型 二、WebRTC中的SDP结构 1. 媒体信息描述 &#xff08;1&#xff09;SDP中媒体信息格式 i. “artpmap”属性 ii. “afmtp”属性 &#xff08;2&#xff09;SSRC与CNAME &#xff08;3&#xff09;举个例子 &…...

Springboot 实践(9)springboot集成Oauth2.0授权包,5个接口文件配置详解

前文讲解实现了spring boot集成Oauth2.0&#xff0c;实现了授权服务器和资源服务器的搭建&#xff0c;并通过浏览器和postman测试&#xff0c;获取到了授权码&#xff0c;用携带授权码的URL能够争取范文到资源。 本文详细讲解spring boot集成Oauth2.0的几个重要文件接口&#…...

最新AI系统ChatGPT程序源码/支持GPT4/自定义训练知识库/GPT联网/支持ai绘画(Midjourney)+Dall-E2绘画/支持MJ以图生图

一、前言 SparkAi系统是基于国外很火的ChatGPT进行开发的Ai智能问答系统。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。 那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧&#xff01…...

【高频面试题】 消息中间件

文章目录 1、RabbitMQ1.1 RabbitMQ-如何保证消息不丢失1.2 RabbitMQ消息的重复消费问题如何解决的1.3 RabbitMQ中死信交换机 ? (RabbitMQ延迟队列有了解过嘛)1.4 RabbitMQ如果有100万消息堆积在MQ , 如何解决(消息堆积怎么解决)1.5 RabbitMQ的高可用机制有了解过嘛 2、Kafka2.…...

物联网智慧安防实训综合实训基地建设方案

一、系统概述 物联网智慧安防实训综合实训基地是一个为学生提供综合实践、培养技能的场所&#xff0c;专注于物联网技术与智慧安防应用的培训和实训。通过物联网智慧安防实训综合实训基地的建设和运营&#xff0c;学生可以在真实的环境中进行实践训练&#xff0c;提高其物联网技…...

openGauss学习笔记-44 openGauss 高级数据管理-存储过程

文章目录 openGauss学习笔记-44 openGauss 高级数据管理-存储过程44.1 语法格式44.2 参数说明44.3 示例 openGauss学习笔记-44 openGauss 高级数据管理-存储过程 存储过程是能够完成特定功能的SQL语句集。用户可以进行反复调用&#xff0c;从而减少SQL语句的重复编写数量&…...

【Linux】进程信号篇Ⅲ:可重入函数、volatile关键字、SIGCHLD信号

信号Ⅲ &#x1f517; 接上篇七、可重入函数八、volatile 关键字九、SIGCHLD 信号 &#x1f517; 接上篇 &#x1f449;&#x1f517;进程信号篇Ⅰ&#xff1a;信号的产生&#xff08;signal、kill、raise、abort、alarm&#xff09;、信号的保存&#xff08;core dump&#x…...

排序算法:冒泡排序

冒泡排序是入门级的算法&#xff0c;但也有一些有趣的玩法。通常来说&#xff0c;冒泡排序有三种写法&#xff1a; 一边比较一边向后两两交换&#xff0c;将最大值 / 最小值冒泡到最后一位&#xff1b;经过优化的写法&#xff1a;使用一个变量记录当前轮次的比较是否发生过交换…...

Spring事件监听源码解析

spring事件监听机制离不开容器IOC特性提供的支持&#xff0c;比如容器会自动创建事件发布器&#xff0c;自动识别用户注册的监听器并进行管理&#xff0c;在特定的事件发布后会找到对应的事件监听器并对其监听方法进行回调。Spring帮助用户屏蔽了关于事件监听机制背后的很多细节…...

Cpp学习——list的模拟实现

目录 一&#xff0c;实现list所需要包含的三个类 二&#xff0c;三个类的实现 1.list_node 2.list类 3.iterator_list类 三&#xff0c;功能实现 1.list类里的push_back() 2.iterator类里的运算符重载 3&#xff0c;list类里面的功能函数 1.insert&#xff08;&#xff…...

工具推荐:Chat2DB一款开源免费的多数据库客户端工具

文章首发地址 Chat2DB是一款开源免费的多数据库客户端工具&#xff0c;适用于Windows和Mac操作系统&#xff0c;可在本地安装使用&#xff0c;也可以部署到服务器端并通过Web页面进行访问。 相较于传统的数据库客户端软件如Navicat、DBeaver&#xff0c;Chat2DB具备了与AIGC…...

C语言刷题指南(二)

&#x1f4d9;作者简介&#xff1a; 清水加冰&#xff0c;目前大二在读&#xff0c;正在学习C/C、Python、操作系统、数据库等。 &#x1f4d8;相关专栏&#xff1a;C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 &#x1f44d…...

[C++11]

文章目录 1. 自动类型推导1.1 auto1.1.1 推导规则1.1.2 auto的限制1.1.3 auto的应用1.1.4 范围for 1.2 decltype1.2.1 推导规则1.2.2 decltype的应用 1.3 返回类型后置 2.可调用对象包装器、绑定器2.1 可调用对象包装器2.1.1 基本用法2.1.2 作为回调函数使用 2.2 绑定器 3. usi…...

【MySQL系列】--初识数据库

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …...

Unity导入google.protobuf失败,无法找到google命名空间

问题&#xff1a; 1.刚开始把protobuf的文件夹直接从其他项目里(unity2021)里复制到unity(2020)版本&#xff0c;当时报错protobuf.dll的依赖项system.memory版本不对。 2.没有使用原来的protobuf文件了。使用vs2019的NuGet管理包来下载Google.Protobuf &#xff0c;仍然报错找…...

使用IDM下载视频出现“由于法律原因,IDM无法下载...

一、问题描述 由于法律原因,IDM无法下载..,如图: 二、原因分析 下载该IDM抓取的M3U8文件,查看其中的内容发现 : #EXT-X-KEY 字段已经写明了加密方式是AES-128,包含一个URI和IV值 #EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:8 #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-KEY:…...

pointnet C++推理部署--tensorrt框架

classification 如上图所示&#xff0c;由于直接export出的onnx文件有两个输出节点&#xff0c;不方便处理&#xff0c;所以编写脚本删除不需要的输出节点193&#xff1a; import onnxonnx_model onnx.load("cls.onnx") graph onnx_model.graphinputs graph.inpu…...

34.Netty源码之Netty如何处理网络请求

highlight: arduino-light 通过前面两节源码课程的学习&#xff0c;我们知道 Netty 在服务端启动时会为创建 NioServerSocketChannel&#xff0c;当客户端新连接接入时又会创建 NioSocketChannel&#xff0c;不管是服务端还是客户端 Channel&#xff0c;在创建时都会初始化自己…...

vscode 安装勾选项解释

1、通过code 打开“操作添加到windows资源管理器文件上下文菜单 &#xff1a;把这个两个勾选上&#xff0c;可以对文件使用鼠标右键&#xff0c;选择VSCode 打开。 2、将code注册为受支持的文件类型的编辑器&#xff1a;不建议勾选&#xff0c;这样会默认使用VSCode打开支持的相…...

Spring 6.0官方文档示例(24): replace-method的用法

一、原始bean定义 package cn.edu.tju.study.service.anno.domain;public class MyValueCalculator {public String computeValue(String input) {return "you inputted: " input;}// some other methods... }二、replace bean定义 package cn.edu.tju.study.serv…...

自然语言处理从入门到应用——LangChain:记忆(Memory)-[聊天消息记录]

分类目录&#xff1a;《自然语言处理从入门到应用》总目录 Cassandra聊天消息记录 Cassandra是一种分布式数据库&#xff0c;非常适合存储大量数据&#xff0c;是存储聊天消息历史的良好选择&#xff0c;因为它易于扩展&#xff0c;能够处理大量写入操作。 # List of contact…...

Python web实战之细说 Django 的单元测试

关键词&#xff1a; Python Web 开发、Django、单元测试、测试驱动开发、TDD、测试框架、持续集成、自动化测试 大家好&#xff0c;今天&#xff0c;我将带领大家进入 Python Web 开发的新世界&#xff0c;深入探讨 Django 的单元测试。通过本文的实战案例和详细讲解&#xff…...

pytorch 42 C#使用onnxruntime部署内置nms的yolov8模型

在进行目标检测部署时,通常需要自行编码实现对模型预测结果的解码及与预测结果的nms操作。所幸现在的各种部署框架对算子的支持更为灵活,可以在模型内实现预测结果的解码,但仍然需要自行编码实现对预测结果的nms操作。其实在onnx opset===11版本以后,其已支持将nms操作嵌入…...