暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Doris 查询优化秘籍(下篇):进阶优化技巧全解析

数据极客圈 2025-02-21
276


在上篇秘籍中,我们深入挖掘了 Doris 查询优化里 Schema 设计、索引优化以及分区裁剪优化扫表的关键策略,这些策略就像给 Doris 这位 “数据大侠” 配上了神兵利器,战斗力直线飙升。今天,咱们接着探索下篇,看看还有哪些进阶技巧,能让 Doris 在数据处理的战场上大杀四方,一路 “狂飙”。


一、同步物化视图:数据查询的 “秘密武器”

同步物化视图就像是一个超级 “数据仓库”,它可不是普通的表,而是提前按照我们定义好的 SELECT 语句,把数据算好存起来。它的存在,就是为了满足我们对原始明细数据各种维度分析的需求,同时还能让固定维度的分析查询快如闪电。


1.1 适用场景:这些情况它最拿手

混合需求场景:当你的分析需求既要查明细数据,又要做固定维度查询时,同步物化视图就像一个全能助手,能轻松应对。

少量数据查询场景:要是查询只涉及表中的少部分列或行,它能精准定位,快速出击,避免在大量数据中 “迷路”。

耗时操作场景:遇到查询里包含像长时间聚合操作这种耗时的 “硬骨头”,同步物化视图提前准备好结果,直接 “交卷”,大大节省时间。

索引匹配场景:当查询需要匹配不同的前缀索引,它也能巧妙应对,让查询顺利进行。

重复子查询场景:对于那些频繁重复使用相同子查询结果的查询,它简直就是 “救星”,直接拿缓存结果,性能提升显著。

而且,Doris 会自动帮我们维护物化视图的数据,保证基础表和物化视图表的数据一致,就像有个勤劳的小管家,不用我们操心额外的维护成本。查询的时候,系统会像个聪明的导航,自动找到最优的物化视图,直接从中读取数据。


1.2 注意事项:使用前要牢记

版本特性:在 Doris 2.0 及后续版本中,物化视图有了更多厉害的功能。不过,在正式生产环境用它之前,最好先在测试环境试试,看看预期的查询能不能命中我们创建的物化视图,就像试驾新车,先摸摸脾气。

避免重复创建:可别在同一张表上创建多个长得差不多的物化视图,这就好比在一个小房间里放多个功能相似的家具,容易挤得慌,还可能导致多个物化视图冲突,让查询命中失败。


1.3 案例展示:实战见真章

假设我们有一张销售记录明细表 sales_records,上面详细记录了每笔交易的各种信息,像交易 ID、销售员 ID、售卖门店 ID、销售日期还有交易金额。我们经常要分析不同门店的销售量。

为了让这些查询跑得更快,我们来创建一个物化视图 store_amt,它按售卖门店分组,把同一门店的销售额加起来。具体步骤如下:

创建同步物化视图:用下面的 SQL 语句创建物化视图 store_amt:


CREATE MATERIALIZED VIEW store_amt AS
SELECT store_id, SUM(sale_amt)
FROM sales_records
GROUP BY store_id;

提交创建任务后,Doris 会在后台偷偷构建这个物化视图。我们可以用下面的命令查看创建进度:


SHOW ALTER TABLE MATERIALIZED VIEW FROM db_name;

当 State 字段变成 FINISHED,就说明 store_amt 物化视图创建成功啦。

  1. 透明改写:物化视图建好后,我们查询不同门店销售量时,Doris 会自动找到 store_amt 物化视图,直接读取预先聚合好的数据,查询效率瞬间起飞。查询语句是这样的:

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

我们还能用 EXPLAIN 命令检查查询有没有成功命中物化视图:


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

在执行计划的末尾,如果看到类似下面这样的内容,那就表示查询成功命中 store_amt 物化视图:


TABLE: default_cluster:test.sales_records(store_amt), PREAGGREGATION: ON

通过这些步骤,我们就利用同步物化视图优化了查询性能,让数据分析效率大幅提升。


二、使用异步物化视图透明改写:高效查询的 “新捷径”

异步物化视图用的是基于 SPJG(SELECT - PROJECT - JOIN - GROUP - BY)模式的透明改写算法,这算法就像一个聪明的侦探,能分析查询 SQL 的结构信息,自动找到合适的物化视图,还能把查询 SQL 改写成利用最优物化视图的形式,用预计算的物化视图结果,大大提高查询性能,降低计算成本。


2.1 案例实操:一步步看明白

创建基础表:先创建 tpch 数据库,再在里面创建 orders 和 lineitem 两张表,并且插入数据。


CREATE DATABASEIFNOTEXISTS tpch;
USE tpch;
CREATETABLEIFNOTEXISTS orders (
   o_orderkey       integernotnull,
   o_custkey        integernotnull,
   o_orderstatus    char(1notnull,
   o_totalprice     decimalv3(15,2notnull,
   o_orderdate      datenotnull,
   o_orderpriority  char(15notnull,
   o_clerk          char(15notnull,
   o_shippriority   integernotnull,
   o_comment        varchar(79notnull
)
DUPLICATEKEY(o_orderkey, o_custkey)
PARTITIONBYRANGE(o_orderdate)(
   FROM ('2023-10-17'TO ('2023-10-20'INTERVAL1DAY
)
DISTRIBUTEDBYHASH(o_orderkey) BUCKETS 3
PROPERTIES ("replication_num" = "1");
INSERTINTO orders VALUES
   (11'o'99.5'2023-10-17''a''b'1'yy'),
   (22'o'109.2'2023-10-18''c','d',2'mm'),
   (33'o'99.5'2023-10-19''a''b'1'yy');
CREATETABLEIFNOTEXISTS lineitem (
   l_orderkey    integernotnull,
   l_partkey     integernotnull,
   l_suppkey     integernotnull,
   l_linenumber  integernotnull,
   l_quantity    decimalv3(15,2notnull,
   l_extendedprice  decimalv3(15,2notnull,
   l_discount    decimalv3(15,2notnull,
   l_tax         decimalv3(15,2notnull,
   l_returnflag  char(1notnull,
   l_linestatus  char(1notnull,
   l_shipdate    datenotnull,
   l_commitdate  datenotnull,
   l_receiptdate datenotnull,
   l_shipinstruct char(25notnull,
   l_shipmode     char(10notnull,
   l_comment      varchar(44notnull
)
DUPLICATEKEY(l_orderkey, l_partkey, l_suppkey, l_linenumber)
PARTITIONBYRANGE(l_shipdate)
(FROM ('2023-10-17'TO ('2023-10-20'INTERVAL1DAY)
DISTRIBUTEDBYHASH(l_orderkey) BUCKETS 3
PROPERTIES ("replication_num" = "1");
INSERTINTO lineitem VALUES
   (12345.56.57.58.5'o''k''2023-10-17''2023-10-17''2023-10-17''a''b''yyyyyyyyy'),
   (22345.56.57.58.5'o''k''2023-10-18''2023-10-18''2023-10-18''a''b''yyyyyyyyy'),
   (32367.58.59.510.5'k''o''2023-10-19''2023-10-19''2023-10-19''c''d''xxxxxxxxx');

创建异步物化视图:基于 tpch benchmark 里的原始表,创建一个异步物化视图 mv1。


CREATE MATERIALIZEDVIEW mv1  
BUILDIMMEDIATEREFRESHCOMPLETEONMANUAL
PARTITIONBY(l_shipdate) 
DISTRIBUTEDBY RANDOM BUCKETS 2
PROPERTIES ('replication_num' = '1')  
AS
SELECT l_shipdate, o_orderdate, l_partkey, l_suppkey, SUM(o_totalprice) AS sum_total 
FROM lineitem 
LEFTJOIN orders ON lineitem.l_orderkey = orders.o_orderkey AND l_shipdate = o_orderdate 
GROUPBY
l_shipdate, 
o_orderdate, 
l_partkey, 
l_suppkey;

使用物化视图进行透明改写:用 explain shape plan 查看查询计划,能看到经过 mv1 透明改写后的计划已经命中 mv1。


mysql> explain shape plan SELECT l_shipdate, SUM(o_totalprice) AS total_price
   -> FROM lineitem
   -> LEFTJOIN orders ON lineitem.l_orderkey = orders.o_orderkey AND l_shipdate = o_orderdate
   -> WHERE l_partkey = 2AND l_suppkey = 3
   -> GROUPBY l_shipdate;
+-------------------------------------------------------------------+
ExplainString(Nereids Planner)                                   |
+-------------------------------------------------------------------+
| PhysicalResultSink                                                |
--PhysicalDistribute[DistributionSpecGather]                      |
----PhysicalProject                                               |
------hashAgg[GLOBAL]                                             |
--------PhysicalDistribute[DistributionSpecHash]                  |
----------hashAgg[LOCAL]                                          |
------------PhysicalProject                                       |
--------------filter((mv1.l_partkey = 2) and (mv1.l_suppkey = 3)) |
----------------PhysicalOlapScan[mv1]                             |
+-------------------------------------------------------------------+

通过 explain 也能查看当前计划经过 mv 改写的状态,比如有没有命中,命中的是哪个 mv 等信息。


2.2 总结与使用建议

通过使用异步物化视图,复杂的连接和聚合查询性能能大幅提升。使用时要注意:

预计算优势:它提前算好查询结果存起来,复杂查询频繁执行时,不用每次都重复计算,超省时间。

减少联接操作:把多个表数据合并到一个视图,查询时减少联接操作,效率自然提高。

自动更新:基表数据变了,物化视图自动更新,保证查询结果是最新的。

空间开销:要额外存储空间存预计算结果,创建时得权衡性能提升和空间消耗。

维护成本:维护物化视图要系统资源和时间,基表频繁更新,物化视图更新开销大,得选合适刷新策略。

适用场景:适合数据变化频率低、查询频率高的场景,数据经常变,实时计算可能更好。

合理利用异步物化视图,能让数据库查询性能在复杂查询和大数据量情况下大幅改善,不过也要综合考虑存储、维护等因素,平衡好性能和成本。


三、使用 Colocate Group 优化 Join:Join 操作的 “高速通道”

Colocate Group 是一种超高效的 Join 方式,它就像给执行引擎修了一条 “高速通道”,能有效避开 Join 操作中数据的 shuffle 开销。具体原理和案例可以参考 Colocation Join。


3.1 注意事项:特殊情况要留意

有时候,就算成功建立了 Colocate Group,执行计划可能还是显示为 Shuffle Join 或 Bucket Shuffle Join。这通常是 Doris 在整理数据,比如在 BE 间迁移 tablet,让数据在多个 BE 之间分布更均衡。

我们可以用命令 show proc "/colocation_group"; 查看 Colocate Group 状态,要是 IsStable 显示 false,那就说明有 Colocate Group 不可用。


四、使用 Hint 调整 Join Shuffle 方式:定制 Join 的 “秘密指令”

Doris 支持用 Hint 来调整 Join 操作中数据 Shuffle 的类型,就像给 Doris 下了定制化的 “秘密指令”,优化查询性能。不过要注意,现在 Doris 基本能自动优化各种场景性能,大部分情况不用我们手动控制 Hint 调优,这部分主要给专业调优人员看,业务人员了解就行。

目前,Doris 有两种独立的 Distribute Hint,[shuffle] 和 [broadcast],用来指定 Join 右表的 Distribute Type。Distribute Type 放在 Join 右表前面,用 [] 括起来。同时,Doris 还能通过 Leading Hint 配合 Distribute Hint,指定 shuffle 方式。


4.1 示例展示:指令怎么用


SELECT COUNT(*) FROM t2 JOIN [broadcast] t1 ON t1.c1 = t2.c2;
SELECT COUNT(*) FROM t2 JOIN [shuffle] t1 ON t1.c1 = t2.c2;


4.2 案例分析:效果看得见

我们用同一个例子看 Distribute Hint 的使用方法。


EXPLAIN SHAPE PLAN SELECT COUNT(*) FROM t1 JOIN t2 ON t1.c1 = t2.c2;

原始 SQL 的计划里,t1 连接 t2 用的是 hash distribute,也就是 DistributionSpecHash 方式。


+----------------------------------------------------------------------------------+ 
ExplainString (Nereids Planner)                                                 | 
+----------------------------------------------------------------------------------+ 
| PhysicalResultSink                                                               | 
--hashAgg [GLOBAL]                                                               | 
----PhysicalDistribute [DistributionSpecGather]                                  | 
------hashAgg [LOCAL]                                                            | 
--------PhysicalProject                                                          | 
----------hashJoin [INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=()| 
------------PhysicalProject                                                      | 
--------------PhysicalOlapScan [t1]                                              | 
------------PhysicalDistribute [DistributionSpecHash]                            | 
--------------PhysicalProject                                                    | 
----------------PhysicalOlapScan [t2]                                            | 
+----------------------------------------------------------------------------------+

加入 [broadcast] hint 后:


EXPLAIN SHAPE PLAN SELECT COUNT(*) FROM t1 JOIN [broadcast] t2 ON t1.c1 = t2.c2;

可以看到 t1 连接 t2 的分发方式变成了 broadcast,也就是 DistributionSpecReplicated 方式。


+----------------------------------------------------------------------------------+ 
| Explain String (Nereids Planner)                                                 | 
+----------------------------------------------------------------------------------+ 
| PhysicalResultSink                                                               | 
| --hashAgg [GLOBAL]                                                               | 
| ----PhysicalDistribute [DistributionSpecGather]                                  | 
| ------hashAgg [LOCAL]                                                            | 
| --------PhysicalProject                                                          | 
| ----------hashJoin [INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=()| 
| ------------PhysicalProject                                                      | 
| --------------PhysicalOlapScan [t1]                                              | 
| ------------PhysicalDistribute [DistributionSpecReplicated]                      | 
| --------------PhysicalProject                                                    | 
| ----------------PhysicalOlapScan [t2]                                            |
+----------------------------------------------------------------------------------+


五、使用 Hint 控制代价改写:优化器的 “精细调控”

查询优化器生成执行计划时,会用基于规则的优化(RBO)和基于代价的优化(CBO)两类规则。RBO 像个按套路出牌的高手,通过预定义的启发式规则改进查询计划,不考虑数据统计信息,比如谓词下推、投影下推。CBO 则像个精打细算的商人,利用数据统计信息估算不同执行计划的代价,选代价最小的执行,像访问路径、连接算法的选择。

有时候,数据库管理员或开发人员想更精细控制查询优化过程,这就可以用查询 Hint 管理 CBO 规则。要注意,Doris 通常能自动优化性能,多数情况不用手工控制 Hint,这部分主要给专业调优人员。


5.1 CBO 规则控制 Hint 语法


SELECT /*+ USE_CBO_RULE(rule1, rule2, ...) */ ...

这个 Hint 紧跟在 SELECT 关键字后面,括号里写要启用的规则名称(规则名称不区分大小写)。目前 Doris 优化器支持好几种代价改写规则,能用 USE_CBO_RULE hint 显式启用,比如 PUSH_DOWN_AGG_THROUGH_JOIN `PUSH_DOWN_AGG_THROUGH


5.2 案例呈现:规则如何发力

咱们来看一个查询示例:


explain shape plan
   select /*+ USE_CBO_RULE(push_down_agg_through_join_one_side) */
           a.event_id,
           b.group_id,
           COUNT(a.event_id)
   from a
   join b on
           a.device_id = b.device_id
   group by
           a.event_id,
           b.group_id
   ;

在这个例子里,我们启用了一个聚合下推的 CBO 规则。这一操作就像是给数据处理流程开辟了一条 “绿色通道”,使得表 a 能够在连接操作之前就进行提前聚合。如此一来,连接时需要处理的数据量大幅减少,从而有效降低了连接的开销,让整个查询过程如同坐上了 “加速快车”,得以快速推进。下压后的计划如下:


PhysicalResultSink
--hashAgg[GLOBAL]
----hashAgg[LOCAL]
------hashJoin[INNER_JOIN] hashCondition=((a.device_id = b.device_id)) otherCondition=()
--------hashAgg[LOCAL]
----------PhysicalOlapScan[a]
--------filter((cast(experiment_id as DOUBLE) = 73.0))
----------PhysicalOlapScan[b]

通过这个案例可以清晰地看到,合理运用 CBO 规则控制 Hint,能够精准地对查询优化过程进行干预,从而显著提升查询性能。


六、使用 Leading Hint 控制 Join 顺序:查询的 “定制导航”

Leading Hint 特性就像是为查询配备了一个 “定制导航”,允许专业调优人员手工指定查询中表的连接顺序,在特定场景下,这一功能对优化复杂查询性能有着显著效果。不过要清楚,当下 Doris 在大多数场景下都能凭借自身强大的自适应能力,将各种查询场景的性能优化得相当出色,所以一般情况下业务人员无需手动通过 Hint 来调整。这部分内容主要是为专业调优人员准备的,业务人员简单知晓即可。


6.1 案例解读:不同场景下的运用


案例 1:调整左右表顺序

对于下面这个查询:


mysql> explain shape plan select from t1 join t2 on t1.c1 = t2.c2;

+------------------------------------------------------------------------------+
| _Explain_ String(Nereids Planner)                                              |
+------------------------------------------------------------------------------+
| PhysicalResultSink                                                           |
--PhysicalDistribute[DistributionSpecGather]                                 |
----PhysicalProject                                                          |
------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
--------PhysicalOlapScan[t1]                                                 |
--------PhysicalDistribute[DistributionSpecHash]                             |
----------PhysicalOlapScan[t2]                                               |
+------------------------------------------------------------------------------+

使用 Leading Hint,可以强制将 join order 指定为 t2 join t1,从而调整原始的连接顺序。


mysql> explain shape plan select/*+ leading(t2 t1) */ * from t1 join t2 on t1.c1 = t2.c2;

+------------------------------------------------------------------------------+
| _Explain_ String(Nereids Planner)                                              |
+------------------------------------------------------------------------------+
| PhysicalResultSink                                                           |
--PhysicalDistribute[DistributionSpecGather]                                 |
----PhysicalProject                                                          |
------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
--------PhysicalOlapScan[t2]                                                 |
--------PhysicalDistribute[DistributionSpecHash]                             |
----------PhysicalOlapScan[t1]                                               |
|                                                                              |
| Hint log:                                                                    |
| Used: leading(t2 t1)                                                         |
| UnUsed:                                                                      |
| SyntaxError:                                                                 |
+------------------------------------------------------------------------------+

从 Hint log 中可以清楚地看到应用成功的 hint:Used: leading (t2 t1) 。这表明通过 Leading Hint,我们成功地按照需求改变了表的连接顺序。


案例 2:强制生成左深树


mysql> explain shape plan select/*+ leading(t1 t2 t3) */ * from t1 join t2 on t1.c1 = t2.c2 join t3 on t2.c2 = t3.c3;

+--------------------------------------------------------------------------------+
| _Explain_ String(Nereids Planner)                                                |
+--------------------------------------------------------------------------------+
| PhysicalResultSink                                                             |
--PhysicalDistribute[DistributionSpecGather]                                   |
----PhysicalProject                                                            |
------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=()   |
--------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
----------PhysicalOlapScan[t1]                                                 |
----------PhysicalDistribute[DistributionSpecHash]                             |
------------PhysicalOlapScan[t2]                                               |
--------PhysicalDistribute[DistributionSpecHash]                               |
----------PhysicalOlapScan[t3]                                                 |
|                                                                                |
| Hint log:                                                                      |
| Used: leading(t1 t2 t3)                                                        |
| UnUsed:                                                                        |
| SyntaxError:                                                                   |
+--------------------------------------------------------------------------------+

同样,从 Hint log 中我们能看到应用成功的 hint:Used: leading (t1 t2 t3) 。这说明通过指定的 Leading Hint,成功强制生成了左深树结构的查询计划。


案例 3:强制生成右深树


mysql> explain shape plan select/*+ leading(t1 {t2 t3}) */ * from t1 join t2 on t1.c1 = t2.c2 join t3 on t2.c2 = t3.c3;

+----------------------------------------------------------------------------------+
| _Explain_ String(Nereids Planner)                                                  |
+----------------------------------------------------------------------------------+
| PhysicalResultSink                                                               |
--PhysicalDistribute[DistributionSpecGather]                                     |
----PhysicalProject                                                              |
------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=()     |
--------PhysicalOlapScan[t1]                                                     |
--------PhysicalDistribute[DistributionSpecHash]                                 |
----------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
------------PhysicalOlapScan[t2]                                                 |
------------PhysicalDistribute[DistributionSpecHash]                             |
--------------PhysicalOlapScan[t3]                                               |
|                                                                                  |
| Hint log:                                                                        |
| Used: leading(t1 { t2 t3 })                                                      |
| UnUsed:                                                                          |
| SyntaxError:                                                                     |
+----------------------------------------------------------------------------------+

这里 Hint log 展示了应用成功的 hint:Used: leading (t1 { t2 t3}) ,意味着通过特定的 Leading Hint 设置,成功实现了强制生成右深树结构的查询计划。


案例 4:强制生成 bushy 树


mysql> explain shape plan select/*+ leading({t1 t2} {t3 t4}) */ * from t1 join t2 on t1.c1 = t2.c2 join t3 on t2.c2 = t3.c3 join t4 on t3.c3 = t4.c4;

+-----------------------------------------------+
| _Explain_ String                                |
+-----------------------------------------------+
| PhysicalResultSink                            |
--PhysicalDistribute                          |
----PhysicalProject                           |
------hashJoin[INNER_JOIN](t2.c2 = t3.c3)     |
--------hashJoin[INNER_JOIN](t1.c1 = t2.c2)   |
----------PhysicalOlapScan[t1]                |
----------PhysicalDistribute                  |
------------PhysicalOlapScan[t2]              |
--------PhysicalDistribute                    |
----------hashJoin[INNER_JOIN](t3.c3 = t4.c4) |
------------PhysicalOlapScan[t3]              |
------------PhysicalDistribute                |
--------------PhysicalOlapScan[t4]            |
|                                               |
| Used: leading({ t1 t2 } { t3 t4 })            |
| UnUsed:                                       |
| SyntaxError:                                  |
+-----------------------------------------------+

从结果中可以看到,Hint log 展示了应用成功的 hint:Used: leading ({t1 t2} { t3 t4 }) ,这表明通过相应的 Leading Hint 设置,成功强制生成了 bushy 树结构的查询计划。


案例 5:view 作为整体参与连接


mysql>  explain shape plan select/*+ leading(alias t1) */count(*) from t1 join (select c2 from t2 join t3 on t2.c2 = t3.c3) asaliason t1.c1 = alias.c2;

+--------------------------------------------------------------------------------------+
| _Explain_ String(Nereids Planner)                                                      |
+--------------------------------------------------------------------------------------+
| PhysicalResultSink                                                                   |
--hashAgg[GLOBAL]                                                                    |
----PhysicalDistribute[DistributionSpecGather]                                       |
------hashAgg[LOCAL]                                                                 |
--------PhysicalProject                                                              |
----------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = alias.c2)) otherCondition=()  |
------------PhysicalProject                                                          |
--------------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
----------------PhysicalProject                                                      |
------------------PhysicalOlapScan[t2]                                               |
----------------PhysicalDistribute[DistributionSpecHash]                             |
------------------PhysicalProject                                                    |
--------------------PhysicalOlapScan[t3]                                             |
------------PhysicalDistribute[DistributionSpecHash]                                 |
--------------PhysicalProject                                                        |
----------------PhysicalOlapScan[t1]                                                 |
|                                                                                      |
| Hint log:                                                                            |
| Used: leading(alias t1)                                                              |
| UnUsed:                                                                              |
| SyntaxError:                                                                         |
+--------------------------------------------------------------------------------------+

这里的 Hint log 展示了应用成功的 hint:Used: leading (alias t1) ,说明在这种情况下,通过 Leading Hint 成功地让 view 作为一个整体按照指定顺序参与了连接操作。


案例 6:DistributeHint 与 LeadingHint 混用


explain shape plan
   select
       nation,
       o_year,
       sum(amount) as sum_profit
   from
       (
           select
               /*+ leading(orders shuffle {lineitem shuffle part} shuffle {supplier broadcast nation} shuffle partsupp) */
              n_name as nation,
               extract(yearfrom o_orderdate) as o_year,
               l_extendedprice * (1 - l_discount) - ps_supplycost * l_quantity as amount
           from
               part,
               supplier,
               lineitem,
               partsupp,
               orders,
               nation
           where
               s_suppkey = l_suppkey
               and ps_suppkey = l_suppkey
               and ps_partkey = l_partkey
               and p_partkey = l_partkey
               and o_orderkey = l_orderkey
               and s_nationkey = n_nationkey
               and p_name like'%green%'
       ) as profit
   groupby
       nation,
       o_year
   orderby
       nation,
       o_year desc;

上述/*+ leading(orders shuffle {lineitem shuffle part} shuffle {supplier broadcast nation} shuffle partsupp) */
这种 hint 指定方式,巧妙地混用了 leading 和 distribute hint 两种格式。其中,leading 用于把控总体的表之间的相对 join 顺序,而 shuffle 和 broadcast 则分别用于指定特定 join 所采用的 shuffle 方式。通过将这两种 Hint 结合使用,专业调优人员能够灵活地对连接顺序和连接方式进行全面控制,从而精准地手工定制出符合用户期望的计划行为。


6.2 使用建议:巧用 Hint 的关键

善用 EXPLAIN:在使用 Leading Hint 时,建议充分利用 EXPLAIN 命令来仔细分析执行计划。这就好比在出发前查看详细的地图,只有这样,才能确保 Leading Hint 能够切实达到我们预期的效果,让查询计划朝着我们期望的方向优化。

动态评估调整:Doris 版本不断升级,业务数据也处于动态变化之中。因此,在这些情况发生时,一定要重新评估 Leading Hint 的效果。就像随着城市的发展,导航路线可能需要适时调整一样,我们要及时记录并根据实际情况对 Leading Hint 进行调整,以保证其始终能为查询性能优化发挥最大作用。


总结

通过对同步物化视图、异步物化视图透明改写、Colocate Group 优化 Join、使用 Hint 调整 Join Shuffle 方式、控制代价改写以及控制 Join 顺序等一系列进阶优化技巧的深入探讨,我们为 Doris 的查询性能优化提供了更为丰富且精细的策略。在实际应用中,可以根据具体的数据特点、业务场景以及性能需求,灵活选择并组合运用这些技巧,让 Doris 在数据处理与查询的征程中一路 “开挂”,高效地为我们的业务赋能。实在搞不定,可以联系社区同学来辅助搞一波~

往期推荐

Doris BE节点下线卡住?快速排障技巧全攻略!

Doris查询报错-230?别慌,教你几招秒解!

Doris Tablet 损坏如何应对?能恢复数据吗?

Doris的Stream Load那些事儿,你踩过哪些“坑”?

如何排查 Apache Doris 中 "Failed to commit txn" 导入失败问题?

Doris的Routine Load导入指南 

Doris 导入慢该如何排查和优化

Doris 建表与分区问题全解析

Doris Schema Change 常见问题分析

Doris 查询优化秘籍(上篇):关键优化策略剖析

Doris 磁盘问题全解析:从挂盘到 Trash 问题,一文读懂!







数据极客圈子介绍

圈子1

Apache Doris社区是目前国内最活跃的开源社区(之一)。Apache Doris(Apache 顶级项目) 聚集了世界全国各地的用户与开发人员,致力于打造一个内容完整、持续成长的互联网开发者学习生态圈! 

如果您对Apache Doris感兴趣,可以通过以下入口访问官方网站、社区论坛、GitHub和dev邮件组

💡官网文档:https://doris.apache.org 
💡社区论坛:https://ask.selectdb.com 
💡GitHub:https://github.com/apache/doris 
💡dev邮件组:dev@doris.apache.org

      可以加作者微信(Faith_xzc)直接进Doris官方社区群
圈子2

PowerData是由一群数据从业人员,因为热爱凝聚在一起,以开源精神为基础,组成的数据开源社区。

社区群内会定期组织模拟面试、线上分享、行业研讨、线下Meetup、城市聚会、求职内推等活动,同时在社区群内你可以进行技术讨论、问题请教,结识更多志同道合的数据朋友。

社区整理了一份每日一题汇总社区分享PPT,内容涵盖大数据组件、编程语言、数据结构与算法、企业真实面试题等各个领域,帮助您提升自我,成功上岸。

可以加作者微信(Faith_xzc)直接进PowrData官方社区群

叮咚✨ “数据极客圈” 向你敞开大门,走对圈子跟对人,行业大咖 “唠” 数据,实用锦囊天天有,就缺你咯!快快关注数据极客圈,共同成长!

 

点击上方公众号关注我们

文章转载自数据极客圈,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论