首页 > 数据库 > > 使用Plan Hint进行调优-运行倾斜
指明查询运行时重分布过程中存在倾斜的重分布键和倾斜值,针对Join和HashAgg运算中的重分布进行优化。
skew(table (column) [(value)])指定中间结果倾斜:
skew((join_rel) (column) [(value)])参数说明
说明:例如:
每一个skew hint用来表示一个表关系存在的倾斜信息,如果想要指定在查询中的多个表关系存在的倾斜信息,则通过指定多个skew hint实现。
在指定skew时,包括以下四个场景的用法:
说明:表关系t的c1列中的v1值在查询执行中存在倾斜。
说明:表关系t的c1列中的v1、v2、v3…等值在查询执行中存在倾斜。
说明:表关系t的c1列的v1值和c2列的v2值在查询执行中存在倾斜。
说明:表关系t的c1列的v1、v3、v5…值和c2列的v2、v4、v6…值在查询执行中存在倾斜。

多列多值时,各组倾斜值间也可以不使用括号,如:skew(t (c1 c2) (v1 v2 v3 v4 v5 v6 ...))。是否使用括号必须统一,不可混合,
如:skew(t (c1 c2) (v1 v2 v3 v4 (v5 v6) ...)) 将会产生语法报错。
如果基表不存在倾斜,而是查询执行中的中间结果出现倾斜,则需要通过指定中间结果倾斜的skew hint来进行倾斜的调优。skew((t1 t2) (c1) (v1))
说明:表关系t1和t2 Join后的结果存在倾斜,倾斜的是t1表的c1列,c1列的倾斜值是v1。
为了避免产生歧义,“c1”只能存在于join_rel的一个表关系中,如果存在同名列则通过别名进行规避。
指定单表倾斜
采用如下查询进行skew hint倾斜调优的举例,查询语句及不带hint的原计划如下所示:
explain
with customer_total_return as
(select sr_customer_sk as ctr_customer_sk
,sr_store_sk as ctr_store_sk
,sum(SR_FEE) as ctr_total_return
from store_returns
,date_dim
where sr_returned_date_sk = d_date_sk
and d_year =2000
group by sr_customer_sk
,sr_store_sk)
select c_customer_id
from customer_total_return ctr1
,store
,customer
where ctr1.ctr_total_return > (select avg(ctr_total_return)*1.2
from customer_total_return ctr2
where ctr1.ctr_store_sk = ctr2.ctr_store_sk)
and s_store_sk = ctr1.ctr_store_sk
and s_state = 'NM'
and ctr1.ctr_customer_sk = c_customer_sk
order by c_customer_id
limit 100;
对内层with子句中的HashAgg和外层的Hash Join进行hint指定,带hint的查询如下:
explain
with customer_total_return as
(select /*+ skew(store_returns(sr_store_sk sr_customer_sk)) */sr_customer_sk as ctr_customer_sk
,sr_store_sk as ctr_store_sk
,sum(SR_FEE) as ctr_total_return
from store_returns
,date_dim
where sr_returned_date_sk = d_date_sk
and d_year =2000
group by sr_customer_sk
,sr_store_sk)
select /*+ skew(ctr1(ctr_customer_sk)(11))*/ c_customer_id
from customer_total_return ctr1
,store
,customer
where ctr1.ctr_total_return > (select avg(ctr_total_return)*1.2
from customer_total_return ctr2
where ctr1.ctr_store_sk = ctr2.ctr_store_sk)
and s_store_sk = ctr1.ctr_store_sk
and s_state = 'NM'
and ctr1.ctr_customer_sk = c_customer_sk
order by c_customer_id
limit 100;该hint表示:内层with子句中的group by在做HashAgg中进行重分布时存在倾斜,对应原计划的10和21号Hash Agg算子;外层ctr1表的ctr_customer_sk列在做Hash Join中进行重分布时存在倾斜,对应原计划的6号算子。生成计划如下所示:

从优化后的计划可以看出:①对于Hash Agg,由于其重分布存在倾斜,所以优化为双层Agg;②对于Hash Join,同样由于其重分布存在倾斜,所以优化为采用新的重分布算子。
不带hint的查询和计划如下:
explain select count(*) from store_sales_1 group by round(ss_list_price);由于hint中列不支持表达式,在进行倾斜优化时需要借助subquery改写查询,改写后的查询和计划如下:
explain
select count(*)
from (select round(ss_list_price),ss_hdemo_sk
from store_sales_1)tmp(a,ss_hdemo_sk)
group by a;

改写注意不要影响到业务逻辑。
采用改写后的查询进行hint,带hint的查询和计划如下:
explain
select /*+ skew(tmp(a)) */ count(*)
from (select round(ss_list_price),ss_hdemo_sk
from store_sales_1)tmp(a,ss_hdemo_sk)
group by a;

从计划可以看出,对Hash Agg进行倾斜优化后,采用了双层agg实现,大大过滤了进行重分布时的数据量,减少了重分布时间。
此外,需要说明的是,对于子查询,支持使用查询内部的列进行hint,如:
explain
select /*+ skew(tmp(b)) */ count(*)
from (select round(ss_list_price) b,ss_hdemo_sk
from store_sales_1)tmp(a,ss_hdemo_sk)
group by a;来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69959250/viewspace-3130426/ ,如需转载,请注明出处,否则将追究法律责任。