华为云云数据库GaussDB指定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章节。
若系统对于查询块没有指定默认别名,则系统会自动按照处理的顺序生成默认块名。一般情况下,每个查询块的默认别名由其所在的查询块名的首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章节。 通过在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)

有时候,优化器阶段的查询重写会展开一些查询块,导致计划在explain中不显示相关查询块。Hint指定查询块是根据优化器阶段之前查询块名字进行指定。当意图获知名字的查询块可能会在计划阶段被展开时,可以加入no_expand的hint(参见指定子查询不展开的Hint章节),让其不被展开。

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的语法说明。

父主题: 使用Plan Hint进行调优

同意关联代理商云淘科技,购买华为云产品更优惠(QQ 78315851)

内容没看懂? 不太想学习?想快速解决? 有偿解决: 联系专家