
# 指定Hint所处的查询块Queryblock
#### 功能描述
该功能允许用户在Hint中通过@queryblock来实现查询块级别的Hint控制，可以指定Hint生效的查询块，比如在外层查询块指定内层查询块的Hint。
#### 语法格式
在Hint的参数最开始加入可缺省的@queryblock，Hint_SEPC为某Hint。
```
Hint_SEPC([@queryblock])
```
#### 参数说明
Hint_SEPC为hint名，@queryblock可缺省，若缺省表示在Hint声明的当前查询块生效。若@queryblock缺省之后导致Hint_SPEC无参，则Hint不需要使用括号，直接写成Hint_SPEC，而非Hint_SPEC()。下面分别从queryblock的命名和Hint生效的方式给出例子。部分Hint无法仅在最外层生效，且不支持通过@queryblock方式指定，具体参见各自Hint的语法说明。
- 查询块QueryBlock的命名： 每个查询块，都需要给出一个名称，以实现对Hint的精确指定。命名方式有两种，用户指定和系统默认指定。
  - 用户可以通过使用blockname的Hint实现对于查询块名称的指定，具体可以参考[子链接块名的hint](https://support.huaweicloud.com/distributed-devg-v3-gaussdb/gaussdb-12-0281.html#ZH-CN_TOPIC_0000002235390025)章节。
  
  - 若系统对于查询块没有指定默认别名，则系统会自动按照处理的顺序生成默认块名。一般情况下，每个查询块的默认别名由其所在的查询块名的首3个字母、"$"、查询块的编号组成，比如第一个select查询块的别名为sel$1。 在pretty模式下，加入blockname开关的explain方式可以查看对于查询中每个表的处理算子所在的查询块名。分布式场景下，只有stream计划才能够以pretty的方式显示，可以通过enable_fast_query_shipping开关辅助生成stream计划。
    ```
    gaussdb=# set explain_perf_mode = pretty;
    SET
    gaussdb=# set enable_fast_query_shipping = off;
    SET
    gaussdb=# explain (blockname on,costs off) select * from t1, (select c1 from t2 group by c1) sub1 where t1.c1 = sub1.c1;
     id |               operation                | Query Block 
    ----+----------------------------------------+-------------
      1 | ->  Streaming (type: GATHER)           | sel$1
      2 |    ->  Hash Join (3,4)                 | sel$1
      3 |       ->  Seq Scan on t1@"sel$1"       | sel$1
      4 |       ->  Hash                         | 
      5 |          ->  HashAggregate             | sel$2
      6 |             ->  Seq Scan on t2@"sel$2" | sel$2
    (6 rows)
    ```
    可以看到t2的扫描在sel$2的查询块中。
    
   

- @queryblock对于查询块的指定： 对于上述例子，修改t2中indexscan的方式：
  ```
  select /*+indexscan(@sel$2 t2) tablescan(t1)*/ * from t1, (select c1 from t2 group by c1) sub1 where t1.c1 = sub1.c1;
  ```
  indexscan和tablescan都为扫描方式的Hint，扫描方式相关的Hint可以参考[SCAN方式的Hint](https://support.huaweicloud.com/distributed-devg-v3-gaussdb/gaussdb-12-0280.html#ZH-CN_TOPIC_0000002200189938)章节。 通过在sel$1的查询块中指定indexscan(@sel$2 t2)的hint，可以将该hint移至查询块sel$2中，对t2生效。若后续改写时查询块sel$2被提升至sel$1，则该Hint也会一起被提升至sel$1，继续对t2生效。
  ```
  gaussdb=# explain (blockname on,costs off) select /*+indexscan(@sel$2 t2) tablescan(t1)*/ * from t1, (select c1 from t2 group by c1) sub1 where t1.c1 = sub1.c1;
   id |                        operation                        | Query Block 
  ----+---------------------------------------------------------+-------------
    1 | ->  Streaming (type: GATHER)                            | sel$1
    2 |    ->  Hash Join (3,4)                                  | sel$1
    3 |       ->  Seq Scan on t1@"sel$1"                        | sel$1
    4 |       ->  Hash                                          | 
    5 |          ->  HashAggregate                              | sel$2
    6 |             ->  Index Only Scan using it2 on t2@"sel$2" | sel$2
  (6 rows)
  ```
  
![](https://support.huaweicloud.com/distributed-devg-v3-gaussdb/public_sys-resources/caution_3.0-zh-cn.png)
有时候，优化器阶段的查询重写会展开一些查询块，导致计划在explain中不显示相关查询块。Hint指定查询块是根据优化器阶段之前查询块名字进行指定。当意图获知名字的查询块可能会在计划阶段被展开时，可以加入no_expand的hint（参见[指定子查询不展开的Hint](https://support.huaweicloud.com/distributed-devg-v3-gaussdb/gaussdb-12-0288.html#ZH-CN_TOPIC_0000002200189946)章节），让其不被展开。
1. 查询块sel$2是简单查询，优化器后续处理时进行查询改写，t1提升至sel$1进行处理，因此计划中没有显示在sel$2查询块的操作。
   ```
   gaussdb=# explain (blockname on,costs off) select * from t2, (select c1 from t1 where t1.c3 = 2) sub1 where t2.c1 = sub1.c1;
    id |                  operation                   | Query Block 
   ----+----------------------------------------------+-------------
     1 | ->  Streaming (type: GATHER)                 | sel$1
     2 |    ->  Nested Loop (3,4)                     | sel$1
     3 |       ->  Index Scan using it3 on t1@"sel$2" | sel$1
     4 |       ->  Index Scan using it2 on t2@"sel$1" | sel$1
   (4 rows)
   ```
   
2. 查询块sel$2是简单查询，优化器后续处理时因为no_expand跳过查询改写，t1还在原查询块处理。
   ```
   gaussdb=# explain (blockname on,costs off) select * from t2, (select /*+ no_expand*/ c1 from t1 where t1.c3 = 2) sub1 where t2.c1 = sub1.c1;
    id |                  operation                   | Query Block 
   ----+----------------------------------------------+-------------
     1 | ->  Streaming (type: GATHER)                 | sel$1
     2 |    ->  Nested Loop (3,4)                     | sel$1
     3 |       ->  Index Scan using it3 on t1@"sel$2" | sel$2
     4 |       ->  Index Scan using it2 on t2@"sel$1" | sel$1
   (4 rows)
   ```
   
3. 通过no_expand知道t1处于sel$2查询块后，可以通过@sel$2进行Hint的查询块指定。
   ```
   explain (blockname on,costs off) select/*+ tablescan(@sel$2 t1)*/ * from t2, (select c1 from t1 where t1.c3 = 2) sub1 where t2.c1 = sub1.c1;
    id |                  operation                   | Query Block 
   ----+----------------------------------------------+-------------
     1 | ->  Streaming (type: GATHER)                 | sel$1
     2 |    ->  Nested Loop (3,4)                     | sel$1
     3 |       ->  Seq Scan on t1@"sel$2"             | sel$1
     4 |       ->  Index Scan using it2 on t2@"sel$1" | sel$1
   (4 rows)
   ```
   
4. view中查询块的编号需要取决于具体使用该view时的语句顺序。因此在创建view中应该避免使用hint指定查询块的功能，否则行为不可控。
   ```
   gaussdb=# create view v1 as select/*+ no_expand */ c1 from t1 where c1 in (select /*+ no_expand */ c1 from t2 where t2.c3=4 );
   CREATE VIEW
   gaussdb=# explain (blockname on,costs off) select  * from v1;
    id |                operation                | Query Block 
   ----+-----------------------------------------+-------------
     1 | ->  Streaming (type: GATHER)            | sel$1
     2 |    ->  Seq Scan on t1@"sel$2"           | sel$2
     3 |       ->  Materialize  [2, SubPlan 1]   | 
     4 |          ->  Streaming(type: BROADCAST) | 
     5 |             ->  Seq Scan on t2@"sel$3"  | sel$3
   (5 rows)
    Predicate Information (identified by plan id) 
   -----------------------------------------------
      2 --Seq Scan on t1@"sel$2"
            Filter: (hashed SubPlan 1)
      5 --Seq Scan on t2@"sel$3"
            Filter: (c3 = 4)
   (4 rows)
   ```
   此时v1中的语句分属于sel$2和sel$3。
   
5. 部分Hint只能在最外层生效，且不支持通过@queryblock方式指定，具体参见各自Hint的语法说明。
 
