八、物化视图
物化视图就是包含了查询结果的数据库对象,可能是对远程数据的本地copy,也可能是一个表或多表join后结果的行或列的子集,也可能是聚合后的结果。说白了,就是预先存储查询结果的一种数据库对象。
在Doris中的物化视图,就是查询结果预先存储起来的特殊的表。
物化视图的出现主要是为了满足用户,既能对原始明细数据的任意维度分析,也能快速的对固定维度进行分析查询。
适用场景
- 1、分析需求覆盖明细数据查询以及固定维度查询两方面;
- 2、查询仅涉及表中的很小一部分列或行;
- 3、查询包含一些耗时处理操作,比如:时间很久的聚合操作等;
- 4、查询需要匹配不同前缀索引。
优势
- 1、对于那些经常重复的使用相同的子查询结果的查询性能大幅提升;
- 2、Doris自动维护物化视图的数据,无论是新的导入,还是删除操作都能保证base表和物化视图表的数据一致性。无需任何额外的人工维护成本;
- 3、查询时,会自动匹配到最优物化视图,并直接从物化视图中读取数据。
自动维护物化视图的数据会造成一些维护开销,会在后面的物化视图的局限性中展开说明。
物化视图和Rollup
在没有物化视图功能之前,用户一般都是使用Rollup功能通过预聚合方式提升查询效率的。但是 Rollup具有一定的局限性,他不能基于明细模型做预聚合。
物化视图则在覆盖了Rollup的功能的同时,还能支持更丰富的聚合函数。所以物化视图其实是Rollup的一个超集。也就是说,之前ALTER TABLE ADD ROLLUP语法支持的功能现在均可以通CREATE MATERIALIZED VIEW实现。
原理
Doris系统提供了一整套对物化视图的DDL语法,包括创建,查看,删除。DDL 的语法和PostgreSQL, Oracle都是一致的。但是Doris目前创建物化视图只能在单表操作,不支持join。
创建物化视图
首先要根据查询语句的特点来决定创建一个什么样的物化视图。并不是说物化视图定义和某个查询语句一模一样就最好。这里有两个原则:
- 从查询语句中抽象出,多个查询共有的分组和聚合方式作为物化视图的定义;
- 不需要给所有维度组合都创建物化视图。
第一点,一个物化视图如果抽象出来,并且多个查询都可以匹配到这张物化视图。这种物化视图效果最好,因为物化视图的维护本身也需要消耗资源。如果物化视图只和某个特殊的查询很贴合,而其他查询均用不到这个物化视图。则会导致这张物化视图的性价比不高,既占用了集群的存储资源,还不能为更多的查询服务。所以用户需要结合自己的查询语句,以及数据维度信息去抽象出一些物化视图的定义。
第二点,在实际的分析查询中,并不会覆盖到所有的维度分析。所以给常用的维度组合创建物化视图即可,从而到达一个空间和时间上的平衡。
通过下面命令就可以创建物化视图了。创建物化视图是一个异步的操作,也就是说用户成功提交创建任务后,Doris会在后台对存量的数据进行计算,直到创建成功。
具体的语法可以通过下面命令查看:HELP CREATE MATERIALIZED VIEW,这里以一个销售记录表为例:
比如我们有一张销售记录明细表,存储了每个交易的时间,销售员,销售门店,和金额。提交完创建物化视图的任务后,Doris就会异步在后台生成物化视图的数据,构建物化视图。在构建期间,用户依然可以正常的查询和导入新的数据。创建任务会自动处理当前的存量数据和所有新到达的增量数据,从而保持和base表的数据一致性。用户不需关心一致性问题。
查询
物化视图创建完成后,用户的查询会根据规则自动匹配到最优的物化视图。比如我们有一张销售记录明细表,并且在这个明细表上创建了三张物化视图。一个存储了不同时间不同销售员的售卖量,一个存储了不同时间不同门店的销售量,以及每个销售员的总销售量。当查询7月19日,各个销售员都买了多少钱时,就可以匹配mv_1物化视图,直接对mv_1 的数据进行查询。
查询自动匹配
物化视图的自动匹配分为下面两个步骤:
- 1、根据查询条件删选出一个最优的物化视图:这一步的输入是所有候选物化视图表的元数据,根据查询的条件从候选集中输出最优的一个物化视图;
*2、根据选出的物化视图对查询进行改写:这一步是结合上一步选择出的最优物化视图,进行查询的改写,最终达到直接查询物化视图的目的。
其中bitmap和hll的聚合函数在查询匹配到物化视图后,查询的聚合算子会根据物化视图的表结构进行改写,如物化视图的查询所示。
最优路径选择
这里分为两个步骤:
- 1、对候选集合进行一个过滤。只要是查询的结果能从物化视图数据计算(取部分行,部分列,或部分行列的聚合)出都可以留在候选集中,过滤完成后候选集合大小>=1。
- 2、从候选集合中根据聚合程度,索引等条件选出一个最优的也就是查询花费最少物化视图。
这里再举一个相对复杂的例子,来体现这个过程:
候选集过滤目前分为4层,每一层过滤后去除不满足条件的物化视图。比如查询7月19日,各个销售员都卖了多少钱,候选集中包括所有的物化视图以及base表共4个:
第一层过滤先判断查询where中的谓词涉及到的数据是否能从物化视图中得到。也就是销售时间列是否在表中存在。由于第三个物化视图中根本不存在销售时间列。所以在这一层过滤中,mv_3就被淘汰了;
第二层是过滤查询的分组列是否为候选集的分组列的子集。也就是销售员id是否为表中分组列的子集。由于第二个物化视图中的分组列并不涉及销售员id。所以在这一层过滤中,mv_2也被淘汰了;
第三层过滤是看查询的聚合列是否为候选集中聚合列的子集。也就是对销售额求和是否能从候选集的表中聚合得出。这里base表和物化视图表均满足标准;
最后一层是过滤看查询需要的列是否存在于候选集合的列中。由于候选集合中的表均满足标准,所以最终候选集合中的表为销售明细表,以及mv_1。
候选集过滤完后输出一个集合,这个集合中的所有表都能满足查询的需求。但每张表的查询效率都不同。这时候就需要再这个集合根据前缀索引是否能匹配到,以及聚合程度的高低来选出一个最优的物化视图。
从表结构中可以看出,base表的销售日期列是一个非排序列,而物化视图表的日期是一个排序列,同时聚合程度上mv_1表明显比base表高。所以最后选择出mv_1作为该查询的最优匹配。
最后再根据选择出的最优解,改写查询。刚才的查询选中mv_1后,将查询改写为从mv_1中读取数据,过滤出日志为7月19日的mv_1中的数据然后返回即可。
查询改写
有些情况下的查询改写还会涉及到查询中的聚合函数的改写,比如业务方经常会用到count distinct对PV、UV进行计算。
例如:广告点击明细记录表中存放哪个用户点击了什么广告,从什么渠道点击的,以及点击的时间。并且在这个base表基础上构建了一个物化视图表,存储了不同广告不同渠道的用户bitmap 值。由于bitmap union这种聚合方式本身会对相同的用户user id进行一个去重聚合。当用户查询广告在web端的uv的时候,就可以匹配到这个物化视图。匹配到这个物化视图表后就需要对查询进行改写,将之前的对用户id求count(distinct)改为对物化视图中bitmap union列求count。所以最后查询取物化视图的第一和第三行求bitmap聚合中有几个值。
使用及限制
- 1、目前支持的聚合函数包括,常用的sum,min,max count,以及计算pv ,uv,留存率,等常用的去重算法hll_union,和用于精确去重计算count(distinct)的算法bitmap_union;
- 2、物化视图的聚合函数的参数不支持表达式仅支持单列,比如: sum(a+b)不支持;
- 3、使用物化视图功能后,由于物化视图实际上是损失了部分维度数据的。所以对表的DML类型操作会有一些限制:如果表的物化视图key中不包含删除语句中的条件列,则删除语句不能执行。比如想要删除渠道为app端的数据,由于存在一个物化视图并不包含渠道这个字段,则这个删除不能执行,因为删除在物化视图中无法被执行。这时候你只能把物化视图先删除,然后删除完数据后,重新构建一个新的物化视图;
- 4、单表上过多的物化视图会影响导入的效率:导入数据时,物化视图和base表数据是同步更新的,如果一张表的物化视图表超过10张,则有可能导致导入速度很慢。这就像单次导入需要同时导入10张表数据是一样的;
- 5、相同列,不同聚合函数,不能同时出现在一张物化视图中,比如:select sum(a),min(a) from table不支持;
- 6、物化视图针对Unique Key数据模型,只能改变列顺序,不能起到聚合的作用,所以在Unique Key模型上不能通过创建物化视图的方式对数据进行粗粒度聚合操作。
示例
示例1
创建表:
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,2,3,'2020-02-02',10);创建物化视图:
create materialized view store_amt as select store_id, sum(sale_amt) from sales_records group by store_id;由于创建物化视图是一个异步的操作,用户在提交完创建物化视图任务后,需要异步地通过命令检查物化视图是否构建完成:
mysql> SHOW ALTER TABLE MATERIALIZED VIEW FROM test;+-------+---------------------+---------------------+---------------------+---------------------+--------------------------------+----------+---------------+----------+------+----------+---------+| JobId | TableName | CreateTime | FinishTime | BaseIndexName | RollupIndexName | RollupId | TransactionId | State | Msg | Progress | Timeout |+-------+---------------------+---------------------+---------------------+---------------------+--------------------------------+----------+---------------+----------+------+----------+---------+| 10599 | example_site_visit2 | 2022-05-14 16:25:23 | 2022-05-14 16:25:44 | example_site_visit2 | rollup_cost_userid | 10600 | 12 | FINISHED | | NULL | 86400 || 10621 | example_site_visit2 | 2022-05-14 16:27:54 | 2022-05-14 16:28:24 | example_site_visit2 | rollup_city_age_cost_maxd_mind | 10622 | 13 | FINISHED | | NULL | 86400 || 10667 | sales_records | 2022-05-14 17:56:50 | 2022-05-14 17:57:14 | sales_records | store_amt | 10668 | 15 | FINISHED | | NULL | 86400 |+-------+---------------------+---------------------+---------------------+---------------------+--------------------------------+----------+---------------+----------+------+----------+---------+3 rows in set (0.00 sec)检验当前查询是否匹配到了合适的物化视图:
mysql> EXPLAIN SELECT store_id, sum(sale_amt) FROM sales_records GROUP BY store_id;+-----------------------------------------------------------------------------------+| Explain String |+-----------------------------------------------------------------------------------+| PLAN FRAGMENT 0 || OUTPUT EXPRS:<slot 2> `store_id` | <slot 3> sum(`sale_amt`) || PARTITION: UNPARTITIONED || || RESULT SINK || || 4:EXCHANGE || || PLAN FRAGMENT 1 || OUTPUT EXPRS: || PARTITION: HASH_PARTITIONED: <slot 2> `store_id` || || STREAM DATA SINK || EXCHANGE ID: 04 || UNPARTITIONED || || 3:AGGREGATE (merge finalize) || | output: sum(<slot 3> sum(`sale_amt`)) || | group by: <slot 2> `store_id` || | cardinality=-1 || | || 2:EXCHANGE || || PLAN FRAGMENT 2 || OUTPUT EXPRS: || PARTITION: HASH_PARTITIONED: `default_cluster:test`.`sales_records`.`record_id` || || STREAM DATA SINK || EXCHANGE ID: 02 || HASH_PARTITIONED: <slot 2> `store_id` || || 1:AGGREGATE (update serialize) || | STREAMING || | output: sum(`sale_amt`) || | group by: `store_id` || | cardinality=-1 || | || 0:OlapScanNode || TABLE: sales_records || PREAGGREGATION: ON || partitions=1/1 || rollup: store_amt || tabletRatio=10/10 || tabletList=10669,10671,10673,10675,10677,10679,10681,10683,10685,10687 || cardinality=0 || avgRowSize=12.0 || numNodes=1 |+-----------------------------------------------------------------------------------+47 rows in set (0.01 sec)删除物化视图:
DROP MATERIALIZED VIEW 物化视图名 on Base表名;案例2:计算pv和uv
假设用户的原始广告点击数据存储在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','app',123);创建物化视图:
create materialized view advertiser_uv asselect advertiser, channel, bitmap_union(to_bitmap(user_id))from advertiser_view_recordgroup by advertiser, channel;在Doris中,count(distinct)聚合的结果和bitmap_union_count聚合的结果是完全一致的。而bitmap_union_count等于bitmap_union的结果求count,所以如果查询中涉及到count(distinct)则通过创建带bitmap_union聚合的物化视图方可加快查询。
因为本身user_id是INT类型,所以在Doris中需要先将字段通过函数to_bitmap转换为bitmap类型然后才可以进行bitmap_union聚合。
检验是否匹配到物化视图:
mysql> explain SELECT advertiser, channel, count(distinct user_id) FROM advertiser_view_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`.`advertiser_view_record`.`mv_bitmap_union_user_id`) || PARTITION: UNPARTITIONED || || RESULT SINK || || 4:EXCHANGE || || PLAN FRAGMENT 1 || OUTPUT EXPRS: || PARTITION: HASH_PARTITIONED: <slot 4> `advertiser`, <slot 5> `channel` || || STREAM DATA SINK || EXCHANGE ID: 04 || UNPARTITIONED || || 3:AGGREGATE (merge finalize) || | output: bitmap_union_count(<slot 6> bitmap_union_count(`default_cluster:test`.`advertiser_view_record`.`mv_bitmap_union_user_id`)) || | group by: <slot 4> `advertiser`, <slot 5> `channel` || | cardinality=-1 || | || 2:EXCHANGE || || PLAN FRAGMENT 2 || OUTPUT EXPRS: || PARTITION: HASH_PARTITIONED: `default_cluster:test`.`advertiser_view_record`.`time` || || STREAM DATA SINK || EXCHANGE ID: 02 || HASH_PARTITIONED: <slot 4> `advertiser`, <slot 5> `channel` || || 1:AGGREGATE (update serialize) || | STREAMING || | output: bitmap_union_count(`default_cluster:test`.`advertiser_view_record`.`mv_bitmap_union_user_id`) || | group by: `advertiser`, `channel` || | cardinality=-1 || | || 0:OlapScanNode || TABLE: advertiser_view_record || PREAGGREGATION: ON || partitions=1/1 || rollup: advertiser_uv || tabletRatio=10/10 || tabletList=10715,10717,10719,10721,10723,10725,10727,10729,10731,10733 || cardinality=0 || avgRowSize=48.0 || numNodes=1 |+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+47 rows in set (0.01 sec)在 EXPLAIN 的结果中,首先可以看到OlapScanNode的rollup属性值为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作为第一列的物化视图就可以解决这个问题。
查询:
mysql> explain select record_id,seller_id,store_id from sales_records where store_id=3;+-----------------------------------------------------------------------------------+| Explain String |+-----------------------------------------------------------------------------------+| PLAN FRAGMENT 0 || OUTPUT EXPRS:`record_id` | `seller_id` | `store_id` || PARTITION: UNPARTITIONED || || RESULT SINK || || 1:EXCHANGE || || PLAN FRAGMENT 1 || OUTPUT EXPRS: || PARTITION: HASH_PARTITIONED: `default_cluster:test`.`sales_records`.`record_id` || || STREAM DATA SINK || EXCHANGE ID: 01 || UNPARTITIONED || || 0:OlapScanNode || TABLE: sales_records || PREAGGREGATION: ON || PREDICATES: `store_id` = 3 || partitions=1/1 || rollup: sales_records || tabletRatio=10/10 || tabletList=10646,10648,10650,10652,10654,10656,10658,10660,10662,10664 || cardinality=1 || avgRowSize=923.0 || numNodes=1 |+-----------------------------------------------------------------------------------+27 rows in set (0.01 sec)创建物化视图:
create materialized view mv_1 asselectstore_id,record_id,seller_id,sale_date,sale_amtfrom sales_records;通过上面语法创建完成后,物化视图中既保留了完整的明细数据,且物化视图的前缀索引为 store_id列。
查看表结构:
mysql> desc sales_records all;+---------------+---------------+-----------+--------+------+-------+---------+-------+---------+| IndexName | IndexKeysType | Field | Type | Null | Key | Default | Extra | Visible |+---------------+---------------+-----------+--------+------+-------+---------+-------+---------+| sales_records | DUP_KEYS | record_id | INT | Yes | true | NULL | | true || | | seller_id | INT | Yes | true | NULL | | true || | | store_id | INT | Yes | true | NULL | | true || | | sale_date | DATE | Yes | false | NULL | NONE | true || | | sale_amt | BIGINT | Yes | false | NULL | NONE | true || | | | | | | | | || mv_1 | DUP_KEYS | store_id | INT | Yes | true | NULL | | true || | | record_id | INT | Yes | true | NULL | | true || | | seller_id | INT | Yes | true | NULL | | true || | | sale_date | DATE | Yes | false | NULL | NONE | true || | | sale_amt | BIGINT | Yes | false | NULL | NONE | true || | | | | | | | | || store_amt | AGG_KEYS | store_id | INT | Yes | true | NULL | | true || | | sale_amt | BIGINT | Yes | false | NULL | SUM | true |+---------------+---------------+-----------+--------+------+-------+---------+-------+---------+14 rows in set (0.00 sec)查询匹配:
mysql> explain select record_id,seller_id,store_id from sales_records where store_id=3;+-----------------------------------------------------------------------------------+| Explain String |+-----------------------------------------------------------------------------------+| PLAN FRAGMENT 0 || OUTPUT EXPRS:`record_id` | `seller_id` | `store_id` || PARTITION: UNPARTITIONED || || RESULT SINK || || 1:EXCHANGE || || PLAN FRAGMENT 1 || OUTPUT EXPRS: || PARTITION: HASH_PARTITIONED: `default_cluster:test`.`sales_records`.`record_id` || || STREAM DATA SINK || EXCHANGE ID: 01 || UNPARTITIONED || || 0:OlapScanNode || TABLE: sales_records || PREAGGREGATION: ON || PREDICATES: `store_id` = 3 || partitions=1/1 || rollup: mv_1 || tabletRatio=10/10 || tabletList=10737,10739,10741,10743,10745,10747,10749,10751,10753,10755 || cardinality=0 || avgRowSize=12.0 || numNodes=1 |+-----------------------------------------------------------------------------------+27 rows in set (0.00 sec)这时候查询就会直接从刚才创建的mv_1物化视图中读取数据。由于物化视图对store_id是存在前缀索引的,查询效率也会提升。
修改表
使用ALTER TABLE命令可以对表进行修改,包括partition 、rollup、schema change、rename和index五种。语法:
ALTER TABLE [database.]tablealter_clause1[, alter_clause2, ...];alter_clause 分为 partition 、rollup、schema change、rename 和 index 五种。rename
将名为 table1的表修改为table2:
ALTER TABLE table1 RENAME table2;将表example_table中名为rollup1的rollup index修改为rollup2:
ALTER TABLE example_table RENAME ROLLUP rollup1 rollup2;将表example_table中名为p1的partition修改为p2:
ALTER TABLE example_table RENAME PARTITION p1 p2;partition
增加分区, 使用默认分桶方式,如现有分区[MIN, 2013-01-01),增加分区[2013-01-01, 2014-01-01):
ALTER TABLE example_db.my_table ADD PARTITION p1 VALUES LESS THAN ("2014-01-01");增加分区,使用新的分桶数:
ALTER TABLE example_db.my_table ADD PARTITION p1 VALUES LESS THAN ("2015-01-01") DISTRIBUTED BY HASH(k1) BUCKETS 20;增加分区,使用新的副本数:
ALTER TABLE example_db.my_table ADD PARTITION p1 VALUES LESS THAN ("2015-01-01") ("replication_num"="1");修改分区副本数:
ALTER TABLE example_db.my_table MODIFY PARTITION p1 SET("replication_num"="1");批量修改指定分区:
ALTER TABLE example_db.my_table MODIFY PARTITION (p1, p2, p4) SET("in_memory"="true");批量修改所有分区:
ALTER TABLE example_db.my_table MODIFY PARTITION (*) SET("storage_medium"="HDD");删除分区:
ALTER TABLE example_db.my_table DROP PARTITION p1;增加一个指定上下界的分区:
ALTER TABLE example_db.my_table ADD PARTITION p1 VALUES [("2014-01-01"), ("2014-02-01"));rollup
创建index: example_rollup_index,基于base index(k1,k2,k3,v1,v2),列式存储:
ALTER TABLE example_db.my_tableADD ROLLUP example_rollup_index(k1, k3, v1, v2);创建index: example_rollup_index2,基于example_rollup_index(k1,k3,v1,v2):
ALTER TABLE example_db.my_table ADD ROLLUP example_rollup_index2 (k1, v1) FROM example_rollup_index;创建index: example_rollup_index3, 基于base index (k1,k2,k3,v1), 自定义rollup超时时间一小时:
ALTER TABLE example_db.my_table ADD ROLLUP example_rollup_index(k1, k3, v1) PROPERTIES("timeout" = "3600");删除index: example_rollup_index2:
ALTER TABLE example_db.my_table DROP ROLLUP example_rollup_index2;表结构变更
使用ALTER TABLE命令可以修改表的Schema,包括:增加列、删除列、修改列类型、改变列顺序。以增加列为例:
我们新增一列uv,类型为BIGINT,聚合类型为SUM,默认值为0:
ALTER TABLE table1 ADD COLUMN uv BIGINT SUM DEFAULT '0' after pv;提交成功后,可以通过以下命令查看作业进度:
SHOW ALTER TABLE COLUMN;当作业状态为FINISHED,则表示作业完成,新的Schema已生效。
查看新的Schema:
DESC table1;可以使用以下命令取消当前正在执行的作业:
CANCEL ALTER TABLE ROLLUP FROM table1;更多可以参阅:HELP ALTER TABLE。
删除数据
Doris目前可以通过两种方式删除数据:DELETE FROM语句和ALTER TABLE DROP PARTITION 语句。
条件删除(drop from)
delete from语句类似标准delete语法,具体使用可以查看help delete;帮助。
语法:
DELETE FROM table_name [PARTITION partition_name]WHEREcolumn_name1 op { value | value_list } [ AND column_name2 op { value| value_list } ...];如:
delete from student_kafka where id=1;注意事项:
- 1、该语句只能针对Partition级别进行删除。如果一个表有多个partition含有需要删除的数据,则需要执行多次针对不同Partition的delete 语句。而如果是没有使用Partition的表,partition的名称即表名;
- 2、where后面的条件谓词只能针对Key列,并且谓词之间,只能通过AND连接。如果想实现OR的语义,需要执行多条delete;
- 3、delete是一个同步命令,命令返回即表示执行成功;
- 4、从代码实现角度,delete是一种特殊的导入操作。该命令所导入的内容,也是一个新的数据版本,只是该版本中只包含命令中指定的删除条件。在实际执行查询时,会根据这些条件进行查询时过滤。所以,不建议大量频繁使用delete命令,因为这可能导致查询效率降低;
- 5、数据的真正删除是在BE进行数据Compaction时进行的。所以执行完delete命令后,并不会立即释放磁盘空间;
- 6、delete命令一个较强的限制条件是,在执行该命令时,对应的表,不能有正在进行的导入任务(包括PENDING、ETL、LOADING)。而如果有QUORUM_FINISHED状态的导入任务,则可能可以执行;
- 7、delete也有一个隐含的类似QUORUM_FINISHED的状态。即如果 delete只在多数副本上完成了,也会返回用户成功。但是会在后台生成一个异步的delete job(Async Delete Job),来继续完成对剩余副本的删除操作。如果此时通过show delete命令,可以看到这种任务在state一栏会显示QUORUM_FINISHED。
分区删除(drop partition)
该命令可以直接删除指定的分区。因为Partition是逻辑上最小的数据管理单元,所以使用DROP PARTITION命令可以很轻量地完成数据删除工作,并且不受load以及任何其他操作的限制,同时不会影响查询效率,是比较推荐的一种数据删除方式。该命令是同步命令,执行成功即生效。而后台数据真正删除的时间可能会延迟10分钟左右。
参考:
https://blog.csdn.net/qq_37475168/article/details/125570856 |