编者荐语:
来自PowerData-徐振超同学的精彩文章!
以下文章来源于数据极客圈 ,作者徐振超
[
数据极客圈 .
一入大数据深似海?别怕!“数据极客圈” 就是你的救生圈,走对圈子跟对人,趣析数据、畅聊趋势,快进圈子!
](#)
在上篇秘籍中,我们深入挖掘了 Doris 查询优化里 Schema 设计、索引优化以及分区裁剪优化扫表的关键策略,这些策略就像给 Doris 这位 “数据大侠” 配上了神兵利器,战斗力直线飙升。今天,咱们接着探索下篇,看看还有哪些进阶技巧,能让 Doris 在数据处理的战场上大杀四方,一路 “狂飙”。
一、同步物化视图:数据查询的 “秘密武器”
同步物化视图就像是一个超级 “数据仓库”,它可不是普通的表,而是提前按照我们定义好的 SELECT 语句,把数据算好存起来。它的存在,就是为了满足我们对原始明细数据各种维度分析的需求,同时还能让固定维度的分析查询快如闪电。
1.1 适用场景:这些情况它最拿手
混合需求场景:当你的分析需求既要查明细数据,又要做固定维度查询时,同步物化视图就像一个全能助手,能轻松应对。
少量数据查询场景:要是查询只涉及表中的少部分列或行,它能精准定位,快速出击,避免在大量数据中 “迷路”。
耗时操作场景:遇到查询里包含像长时间聚合操作这种耗时的 “硬骨头”,同步物化视图提前准备好结果,直接 “交卷”,大大节省时间。
索引匹配场景:当查询需要匹配不同的前缀索引,它也能巧妙应对,让查询顺利进行。
重复子查询场景:对于那些频繁重复使用相同子查询结果的查询,它简直就是 “救星”,直接拿缓存结果,性能提升显著。
而且,Doris 会自动帮我们维护物化视图的数据,保证基础表和物化视图表的数据一致,就像有个勤劳的小管家,不用我们操心额外的维护成本。查询的时候,系统会像个聪明的导航,自动找到最优的物化视图,直接从中读取数据。
1.2 注意事项:使用前要牢记
避免重复创建:可别在同一张表上创建多个长得差不多的物化视图,这就好比在一个小房间里放多个功能相似的家具,容易挤得慌,还可能导致多个物化视图冲突,让查询命中失败。
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 物化视图创建成功啦。
- 透明改写:物化视图建好后,我们查询不同门店销售量时,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(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。
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 在数据处理与查询的征程中一路 “开挂”,高效地为我们的业务赋能。实在搞不定,可以联系社区同学来辅助搞一波~
往期推荐
[
](http://mp.weixin.qq.com/s?__b...
Doris的Stream Load那些事儿,你踩过哪些“坑”?
如何排查 Apache Doris 中 "Failed to commit txn" 导入失败问题?
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邮件组:mailto:dev@doris.apache.org
可以加作者微信(Faith\_xzc)直接进Doris官方社区群
圈子2
PowerData是由一群数据从业人员,因为热爱凝聚在一起,以开源精神为基础,组成的数据开源社区。
社区整理了一份每日一题汇总及社区分享PPT,内容涵盖大数据组件、编程语言、数据结构与算法、企业真实面试题等各个领域,帮助您提升自我,成功上岸。
可以加作者微信(Faith\_xzc)直接进PowrData官方社区群
叮咚✨ “数据极客圈” 向你敞开大门,走对圈子跟对人,行业大咖 “唠” 数据,实用锦囊天天有,就缺你咯!快快关注数据极客圈,共同成长!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。