
# Plan Hint调优概述
Plan Hint为用户提供了直接影响执行计划生成的手段，用户可以通过指定join顺序，join、stream、scan方法，指定结果行数，指定重分布过程中的倾斜信息等多个手段来进行执行计划的调优，以提升查询的性能。
GaussDB还提供了SQL PATCH功能，在不修改业务语句的前提下通过创建SQL PATCH的方式使得Hint生效。
#### 功能描述
Plan Hint支持在SELECT、INSERT、UPDATE、DELETE、MERGE等关键字后通过如下形式指定：
```
/*+ <plan hint>*/
```
可以同时指定多个hint，之间使用空格分隔。hint只能hint当前层的计划，对于子查询计划的hint，需要在子查询的select关键字后指定hint。
例如：
```
select /*+ <plan_hint1> <plan_hint2> */ * from t1, (select /*+ <plan_hint3> */ * from t2) where 1=1;
```
其中\<plan_hint1\>，\<plan_hint2\>为外层查询的hint，\<plan_hint3\>为内层子查询的hint。
检查Plan Hint调优的效果可以借助explain语法进行分析。通过explain可以查看使用Plan Hint后目标SQL的计划，对比计划是否符合要求以验证Plan Hint的效果。explain有多种计划展示的模式，通过explain_perf_mode进行控制。本节的示例一般通过设置explain_perf_mode为pretty模式来展示计划，展示较全的计划相关信息。部分示例设置explain_perf_mode为normal模式以精简输出信息。
![](https://support.huaweicloud.com/distributed-devg-v2-gaussdb/public_sys-resources/notice_3.0-zh-cn.png)
如果在视图定义（CREATE VIEW）时指定hint，则在该视图每次被应用时会使用该hint。
当使用random plan功能（参数plan_mode_seed不为0）时，查询指定的plan hint不会被使用。
#### 支持范围
当前版本Plan Hint支持的范围如下，后续版本会进行增强。
- 指定Join顺序的hint - leading hint。
- 指定Join方式的hint，仅支持除semi/anti join，unique plan之外的常用hint。
- 指定结果集行数的hint。
- 指定Stream方式的hint。
- 指定Scan方式的hint，仅支持常用的tablescan，indexscan和indexonlyscan的hint。
- 指定子链接块名的hint。
- 指定倾斜信息的hint，仅支持Join与HashAgg的重分布过程倾斜。
- 指定本query内生效的guc参数的hint（在视图内使用不生效）。
- 指定使用custom plan或generic plan的hint（只对PBE执行的查询语句生效）。
- 指定子查询不展开的hint。
- 指定当前查询语句不进入全局计划缓存（enable_global_plancache打开且当前语句为PBE执行时生效）。
#### 注意事项
- 不支持Agg、Sort、Setop和Subplan的hint。
- 不支持SMP和Node Group场景下的Hint。
 
#### 示例
本章节使用同一个语句进行示例，便于Plan Hint支持的各方法作对比，示例语句及不带hint的原计划如下所示：
```
explain
select i_product_name product_name
,i_item_sk item_sk
,s_store_name store_name
,s_zip store_zip
,ad2.ca_street_number c_street_number
,ad2.ca_street_name c_street_name
,ad2.ca_city c_city
,ad2.ca_zip c_zip
,count(*) cnt
,sum(ss_wholesale_cost) s1
,sum(ss_list_price) s2
,sum(ss_coupon_amt) s3
FROM   store_sales
,store_returns
,store
,customer
,promotion
,customer_address ad2
,item
WHERE  ss_store_sk = s_store_sk AND
ss_customer_sk = c_customer_sk AND
ss_item_sk = i_item_sk and
ss_item_sk = sr_item_sk and
ss_ticket_number = sr_ticket_number and
c_current_addr_sk = ad2.ca_address_sk and
ss_promo_sk = p_promo_sk and
i_color in ('maroon','burnished','dim','steel','navajo','chocolate') and
i_current_price between 35 and 35 + 10 and
i_current_price between 35 + 1 and 35 + 15
group by i_product_name
,i_item_sk
,s_store_name
,s_zip
,ad2.ca_street_number
,ad2.ca_street_name
,ad2.ca_city
,ad2.ca_zip
;
```
```
HashAggregate  (cost=53.53..53.76 rows=1 width=880)
   Group By Key: item.i_product_name, item.i_item_sk, store.s_store_name, store.s_zip, ad2.ca_street_number, ad2.ca_street_name, ad2.ca_city, ad2.ca_zip
   ->  Streaming (type: GATHER)  (cost=53.53..53.76 rows=2 width=880)
         Node/s: All datanodes
         ->  HashAggregate  (cost=53.10..53.11 rows=2 width=880)
               Group By Key: item.i_product_name, item.i_item_sk, store.s_store_name, store.s_zip, ad2.ca_street_number, ad2.ca_street_name, ad2.ca_city, ad2.ca_zip
               ->  Nested Loop  (cost=0.00..53.07 rows=2 width=776)
                     ->  Streaming(type: REDISTRIBUTE)  (cost=0.00..46.36 rows=2 width=416)
                           Spawn on: All datanodes
                           ->  Nested Loop  (cost=0.00..45.99 rows=2 width=416)
                                 ->  Streaming(type: REDISTRIBUTE)  (cost=0.00..39.27 rows=2 width=258)
                                       Spawn on: All datanodes
                                       ->  Nested Loop  (cost=0.00..38.99 rows=2 width=258)
                                             ->  Streaming(type: REDISTRIBUTE)  (cost=0.00..32.28 rows=2 width=262)
                                                   Spawn on: All datanodes
                                                   ->  Nested Loop  (cost=0.00..32.00 rows=2 width=262)
                                                         ->  Streaming(type: REDISTRIBUTE)  (cost=0.00..25.28 rows=2 width=262)
                                                               Spawn on: All datanodes
                                                               ->  Nested Loop  (cost=0.00..25.00 rows=2 width=262)
                                                                     ->  Nested Loop  (cost=0.00..21.64 rows=2 width=270)
                                                                           ->  Seq Scan on item  (cost=0.00..13.36 rows=1 width=208)
                                                                                 Filter: ((i_current_price >= 35::numeric) AND (i_current_price <= 45::numeric) AND (i_current_price >= 36::numeric) AND
 (i_current_price <= 50::numeric) AND (i_color = ANY ('{maroon,burnished,dim,steel,navajo,chocolate}'::bpchar[])))
                                                                           ->  Index Scan using store_sales_pkey on store_sales  (cost=0.00..8.27 rows=1 width=62)
                                                                                 Index Cond: (ss_item_sk = item.i_item_sk)
                                                                     ->  Index Only Scan using store_returns_pkey on store_returns  (cost=0.00..3.35 rows=1 width=8)
                                                                           Index Cond: ((sr_item_sk = store_sales.ss_item_sk) AND (sr_ticket_number = store_sales.ss_ticket_number))
                                                         ->  Index Scan using customer_pkey on customer  (cost=0.00..3.35 rows=1 width=8)
                                                               Index Cond: (c_customer_sk = store_sales.ss_customer_sk)
                                             ->  Index Only Scan using promotion_pkey on promotion  (cost=0.00..3.35 rows=1 width=4)
                                                   Index Cond: (p_promo_sk = store_sales.ss_promo_sk)
                                 ->  Index Scan using store_pkey on store  (cost=0.00..3.35 rows=1 width=166)
                                       Index Cond: (s_store_sk = store_sales.ss_store_sk)
                     ->  Index Scan using customer_address_pkey on customer_address ad2  (cost=0.00..3.35 rows=1 width=368)
                           Index Cond: (ca_address_sk = customer.c_current_addr_sk)
(34 rows)
```
