首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Doris 查询优化秘籍(下篇):进阶优化技巧全解析

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

作者头像
数据极客圈
发布2025-07-14 17:23:35
发布2025-07-14 17:23:35
18300
代码可运行
举报
运行总次数:0
代码可运行

在上篇秘籍中,我们深入挖掘了 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:

代码语言:javascript
代码运行次数:0
运行
复制

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

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

代码语言:javascript
代码运行次数:0
运行
复制

SHOW ALTER TABLE MATERIALIZED VIEW FROM db_name;

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

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

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

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

代码语言:javascript
代码运行次数:0
运行
复制

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

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

代码语言:javascript
代码运行次数:0
运行
复制

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

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

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

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

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

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

代码语言:javascript
代码运行次数:0
运行
复制

CREATE DATABASEIFNOTEXISTS tpch;
USE tpch;
CREATETABLEIFNOTEXISTS orders (
   o_orderkey       integernotnull,
   o_custkey        integernotnull,
   o_orderstatus    char(1) notnull,
   o_totalprice     decimalv3(15,2) notnull,
   o_orderdate      datenotnull,
   o_orderpriority  char(15) notnull,
   o_clerk          char(15) notnull,
   o_shippriority   integernotnull,
   o_comment        varchar(79) notnull
)
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
   (1, 1, 'o', 99.5, '2023-10-17', 'a', 'b', 1, 'yy'),
   (2, 2, 'o', 109.2, '2023-10-18', 'c','d',2, 'mm'),
   (3, 3, '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,2) notnull,
   l_extendedprice  decimalv3(15,2) notnull,
   l_discount    decimalv3(15,2) notnull,
   l_tax         decimalv3(15,2) notnull,
   l_returnflag  char(1) notnull,
   l_linestatus  char(1) notnull,
   l_shipdate    datenotnull,
   l_commitdate  datenotnull,
   l_receiptdate datenotnull,
   l_shipinstruct char(25) notnull,
   l_shipmode     char(10) notnull,
   l_comment      varchar(44) notnull
)
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
   (1, 2, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-10-17', '2023-10-17', '2023-10-17', 'a', 'b', 'yyyyyyyyy'),
   (2, 2, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-10-18', '2023-10-18', '2023-10-18', 'a', 'b', 'yyyyyyyyy'),
   (3, 2, 3, 6, 7.5, 8.5, 9.5, 10.5, 'k', 'o', '2023-10-19', '2023-10-19', '2023-10-19', 'c', 'd', 'xxxxxxxxx');

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

代码语言:javascript
代码运行次数:0
运行
复制

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。

代码语言:javascript
代码运行次数:0
运行
复制

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 示例展示:指令怎么用

代码语言:javascript
代码运行次数:0
运行
复制

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 的使用方法。

代码语言:javascript
代码运行次数:0
运行
复制

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

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

代码语言:javascript
代码运行次数:0
运行
复制

+----------------------------------------------------------------------------------+ 
| 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 后:

代码语言:javascript
代码运行次数:0
运行
复制

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

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

代码语言:javascript
代码运行次数:0
运行
复制

+----------------------------------------------------------------------------------+ 
| 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 语法

代码语言:javascript
代码运行次数:0
运行
复制

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

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

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

咱们来看一个查询示例:

代码语言:javascript
代码运行次数:0
运行
复制

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 能够在连接操作之前就进行提前聚合。如此一来,连接时需要处理的数据量大幅减少,从而有效降低了连接的开销,让整个查询过程如同坐上了 “加速快车”,得以快速推进。下压后的计划如下:

代码语言:javascript
代码运行次数:0
运行
复制

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:调整左右表顺序

对于下面这个查询:

代码语言:javascript
代码运行次数:0
运行
复制

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,从而调整原始的连接顺序。

代码语言:javascript
代码运行次数:0
运行
复制

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:强制生成左深树
代码语言:javascript
代码运行次数:0
运行
复制

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:强制生成右深树
代码语言:javascript
代码运行次数:0
运行
复制

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 树
代码语言:javascript
代码运行次数:0
运行
复制

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 作为整体参与连接
代码语言:javascript
代码运行次数:0
运行
复制

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 混用
代码语言:javascript
代码运行次数:0
运行
复制

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 在数据处理与查询的征程中一路 “开挂”,高效地为我们的业务赋能。实在搞不定,可以联系社区同学来辅助搞一波~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-02-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据极客圈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、同步物化视图:数据查询的 “秘密武器”
    • 1.1 适用场景:这些情况它最拿手
    • 1.2 注意事项:使用前要牢记
    • 1.3 案例展示:实战见真章
  • 二、使用异步物化视图透明改写:高效查询的 “新捷径”
    • 2.1 案例实操:一步步看明白
    • 2.2 总结与使用建议
  • 三、使用 Colocate Group 优化 Join:Join 操作的 “高速通道”
    • 3.1 注意事项:特殊情况要留意
  • 四、使用 Hint 调整 Join Shuffle 方式:定制 Join 的 “秘密指令”
    • 4.1 示例展示:指令怎么用
    • 4.2 案例分析:效果看得见
  • 五、使用 Hint 控制代价改写:优化器的 “精细调控”
    • 5.1 CBO 规则控制 Hint 语法
    • 5.2 案例呈现:规则如何发力
  • 六、使用 Leading Hint 控制 Join 顺序:查询的 “定制导航”
    • 6.1 案例解读:不同场景下的运用
      • 案例 1:调整左右表顺序
      • 案例 2:强制生成左深树
      • 案例 3:强制生成右深树
      • 案例 4:强制生成 bushy 树
      • 案例 5:view 作为整体参与连接
      • 案例 6:DistributeHint 与 LeadingHint 混用
    • 6.2 使用建议:巧用 Hint 的关键
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档