# plan management
由于数据库参数设置的更改、版本的升级、数据的变化等，导致同一个语句的执行计划会存在差异，同时造成执行性能的劣化。plan management可通过为语句绑定指定的计划来防止计划跳变而产生的性能劣化。
plan management主要包括为计划生成唯一标识、为语句和计划生成sql_hash和plan_hash、计划保存和使用、计划失效等部分。
#### 为计划生成唯一标识
如果要为语句指定一个固定的计划，那么每个语句及其计划必须拥有一个唯一的标识，即sql_hash和plan_hash。
可以通过开启GUC参数[enable_generate_plan_hash](https://support.huaweicloud.com/devg-911-dws/dws_04_1088.html#ZH-CN_TOPIC_0000002202094217__section8354162813289)为outline生成唯一标识plan_hash。
#### 适用于生成outline的计划
除FQS和CN强量化计划外，其他计划都会生成outline。
#### outline保存和使用
下图是outline保存和使用在语句执行过程中处理流程。
图1outline保存和使用流程   
![](https://support.huaweicloud.com/devg-911-dws/figure/zh-cn_image_0000002267728162.png "点击放大")
**outline保存**
outline保存，即将计划自动生成的outline记录到[SQL_OUTLINE](https://support.huaweicloud.com/devg-911-dws/dws_04_10092.html)系统表中，以供后续将其绑定给SQL语句。
- 如果同一个sql_hash的语句不存在该outline_name的outline，则保存该outline；若已经存在同名的outline，则不会重复保存。
- outline是在语句正确执行完成后才进行保存的，如果执行出错，则不会保存。
可以通过设置GUC参数[planmgmt_options](https://support.huaweicloud.com/devg-911-dws/dws_04_1088.html#ZH-CN_TOPIC_0000002202094217__section1036404625113)来保存outline，例如：
- 设置planmgmt_options = 'plan_save_mode_outline, plan_save_level_topsql'，满足记录topsql的语句才将其outline进行保存。 或
  
- 设置planmgmt_options = 'plan_save_mode_outline, plan_save_level_all'，表示将outline进行保存。
![](https://support.huaweicloud.com/devg-911-dws/public_sys-resources/note_3.0-zh-cn.png)
plan management虽可以使语句执行性能稳定，但启用plan management也存在性能消耗，不适用于非资源消耗型的简单语句。因此建议设置planmgmt_options = 'plan_save_mode_outline, plan_save_level_topsql'，可避免将简单语句的计划也进行保存。
**outline使用**
使用pgxc_bind_plan函数为语句绑定一个outline后，可设置planmgmt_options = 'plan_save_mode_outline, plan_save_level_topsql, enable_plan_baseline'，使得执行语句时可以使用该绑定的outline。
![](https://support.huaweicloud.com/devg-911-dws/public_sys-resources/notice_3.0-zh-cn.png)
当前通过plan management支持自动提取以下hint：支持join顺序的leading hint、join方式的hint、scan方式的hint、指定倾斜列的skew hint和指定分布方式的stream hint。
通过plan management绑定outline来固定计划的根本是通过outline中的hint来固定计划，由于outline中支持自动提取的hint类型有限，有以下约束：
1. 如果sql中手工增删或修改了outline中不支持的hint，可能会出现绑定outline后，计划不能被固定：
   - no merge hint：sql1中指定了no merge hint，sql2和sql1的差别仅在于没有指定no merge hint，sql1和sql2的sql_hash是一样的，所以进行outline绑定就会同时给sql1和sql2都绑定，如果绑定的是sql1生成的outline，则sql2执行时绑定的outline就会不生效，同理反过来也是成立的。这是因为no merge hint限制了子查询的提升，语句块的层次不同，生成的outline中的hint应用的语句块在子查询提升和不提升时是不一样的，所以会导致绑定后无法找到hint中对应的表而无法生效。
   
   - GUC hint：与no merge hint同理。
    
2. 可通过人工修改自动生成的outline，添加outline中不支持自动提取的hint，来固定计划。
 
#### plan management使用示例
1. 设置开启plan management。 
   ```
   SET resource_track_cost=0;
   SET resource_track_duration=0;
   SET enable_generate_plan_hash = on;
   SET planmgmt_options='plan_save_mode_outline,plan_save_level_topsql,enable_plan_baseline';
   ```
   
   
2. 连接数据库创建表和索引。 
   ```
   CREATE TABLE t1(a1 int, b1 int, c1 serial) DISTRIBUTE BY hash(a1);
   INSERT INTO t1(a1, b1) VALUES(generate_series(1, 10), generate_series(1, 8));
   CREATE INDEX idx_t1_b1 on t1(b1);
   CREATE TABLE t2(a2, b2, c2) AS SELECT * FROM t1;
   ```
   
   
3. 查看不使用索引和使用索引两个语句的计划。 
   查看不使用索引的语句计划：
   ```
   EXPLAIN (verbose on, blockname on, outline on) select count(*) from t1, t2 where b1 = 1 and a1 = a2;
   ```
   ![](https://support.huaweicloud.com/devg-911-dws/figure/zh-cn_image_0000002267831248.png "点击放大")
   查看使用索引的语句计划：
   ```
   EXPLAIN (verbose on, blockname on, outline on) select /*+ indexscan(t1 idx_t1_b1) */ count(*) from t1, t2 where b1 = 1 and a1 = a2;
   ```
   ![](https://support.huaweicloud.com/devg-911-dws/figure/zh-cn_image_0000002302401177.png "点击放大")
   
   
4. 查看sql_outline表中保存的计划。 
   ```
   SELECT sql_hash, plan_hash, outline_name, outline FROM dbms_om.sql_outline WHERE outline like '%public.t1%public.t2%';
   ```
   ![](https://support.huaweicloud.com/devg-911-dws/figure/zh-cn_image_0000002302368077.png "点击放大")
   使用索引的语句对应的sql_hash、plan_hash和outline_name分别为'sql_6e8591b8291c3b458b26ce7419fd3704'和'plan_00df934ed2620cb09c5f51a33f1945fd'和'outline_ae16ae6300416c3efc96378c7b3a7e7b'。
   
   
5. 为语句绑定使用索引的计划。 
   ```
   SELECT pgxc_bind_plan('sql_6e8591b8291c3b458b26ce7419fd3704', 'outline_ae16ae6300416c3efc96378c7b3a7e7b');
    pgxc_bind_plan
   ----------------
    t
   (1 row)
   ```
   
   
6. 查看语句是否使用了绑定的索引计划。 
   ```
   EXPLAIN (verbose on, blockname on, outline on) select count(*) from t1, t2 where b1 = 1 and a1 = a2;
   ```
   ![](https://support.huaweicloud.com/devg-911-dws/figure/zh-cn_image_0000002267728166.png "点击放大")
   从上面的计划可见，绑定的索引计划被使用。
   
   
7. 为语句解绑计划。 
   ```
   SELECT pgxc_unbind_plan('sql_6e8591b8291c3b458b26ce7419fd3704');
    pgxc_unbind_plan
   ------------------
    t
   (1 row)
   ```
   
   
8. 查看解绑计划后的执行计划。 
   ```
   EXPLAIN (verbose on, blockname on, outline on) select count(*) from t1, t2 where b1 = 1 and a1 = a2;
   ```
   ![](https://support.huaweicloud.com/devg-911-dws/figure/zh-cn_image_0000002267831252.png "点击放大")
   从上面的计划可见，索引计划不再被使用。
   
   
9. 重新绑定计划，删除索引。 
   ```
   SELECT pgxc_bind_plan('sql_6e8591b8291c3b458b26ce7419fd3704', 'outline_ae16ae6300416c3efc96378c7b3a7e7b');
    pgxc_bind_plan
   ----------------
    t
   (1 row)
   DROP INDEX idx_t1_b1;
   ```
   
   
10. 查看计划失效后的语句执行计划。 
    ```
    EXPLAIN (verbose on, blockname on, outline on) select count(*) from t1, t2 where b1 = 1 and a1 = a2;
    ```
    ![](https://support.huaweicloud.com/devg-911-dws/figure/zh-cn_image_0000002302401181.png "点击放大")
    从上面的计划可见，虽然绑定的outline被使用，但绑定的outline中的索引hint由于索引删除，导致索引hint未生效。
    
    
11. 含no merge hint的语句的计划。 
    ```
    EXPLAIN (verbose on, blockname on, outline on) select * from t1 where a1 in (select /*+ no merge */ a2 from t2 where b2 < 10);
    ```
    ![](https://support.huaweicloud.com/devg-911-dws/figure/zh-cn_image_0000002302368081.png "点击放大")
    
    
12. 无no merge hint的语句的计划。 
    ```
    EXPLAIN (verbose on, blockname on, outline on) select * from t1 where a1 in (select a2 from t2 where b2 < 10);
    ```
    ![](https://support.huaweicloud.com/devg-911-dws/figure/zh-cn_image_0000002267728170.png "点击放大")
    
    
13. 查询含no merge hint和无no merge hint生成的outline。 
    ```
    SELECT sql_hash, plan_hash, outline_name, outline FROM dbms_om.sql_outline WHERE sql_hash = 'sql_14150502dc61e290b4c81c5c43d7446c';
    ```
    ![](https://support.huaweicloud.com/devg-911-dws/figure/zh-cn_image_0000002267831256.png "点击放大")
    
    
14. 绑定含no merge hint的outline。 
    ```
    SELECT pgxc_bind_plan('sql_14150502dc61e290b4c81c5c43d7446c', 'outline_a2cdc54106b991174cc0a35b8e0f0b29');
     pgxc_bind_plan
    ----------------
     t
    (1 row)
    ```
    
    
15. 对无no merge hint的语句，应用绑定的outline后，仍产生了子查询提升。 
    ```
    EXPLAIN (verbose on, blockname on, outline on) select * from t1 where a1 in (select a2 from t2 where b2 < 10);
    ```
    ![](https://support.huaweicloud.com/devg-911-dws/figure/zh-cn_image_0000002302401185.png "点击放大")
    
    
16. 人工修改绑定的outline添加no merge hint，并重新创建到dbms_om.sql_outline中。 
    ```
    CREATE OUTLINE outline_nomerge for sql_14150502dc61e290b4c81c5c43d7446c using
    '/*+
        begin_outline_data
         no merge@"sel$2"
         TableScan(@"sel$1" public.t1@"sel$1")
         TableScan(@"sel$2" public.t2@"sel$2")
        end_outline_data
     */'
    ```
    
    
17. 将新创建的含no merge hint的outline进行绑定。 
    ```
    SELECT pgxc_bind_plan('sql_14150502dc61e290b4c81c5c43d7446c', 'outline_nomerge');
     pgxc_bind_plan
    ----------------
     t
    (1 row)
    ```
    
    
18. 对无no merge hint的语句，应用绑定的outline后，不再产生子查询提升。 
    ```
    EXPLAIN (verbose on, blockname on, outline on) select * from t1 where a1 in (select a2 from t2 where b2 < 10);
    ```
    ![](https://support.huaweicloud.com/devg-911-dws/figure/zh-cn_image_0000002302368085.png "点击放大")
    
    
 
