多表hint

use_nl (A , B)

use_nl ::=

  1. 如果A、B都是基表,则表示以A作为外表,B作为内表,两者做nestloop连接。
  2. 如果A是表集合,B是基表,定义A=(table1, table2, ... ,table n)。此时的语义为:以集合A内各表做连接得到的联接表作为外表,B作为内表,两者做nestloop连接。(当B是表集合、A是基表时情况类似)
  3. 如果A、B均是表集合,则表示以集合A内各表做连接得到的联接表作为外表,以集合B内各表做连接得到的联接表作为内表,两者做nestloop连接。

举例:

--  清理环境
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;

--  创建表
CREATE TABLE a(a1 INT, a2 INT);
CREATE TABLE b(b1 INT, b2 INT);
CREATE TABLE c(c1 INT, c2 INT);


explain select /*+ use_nl(c,(a,b))*/ * from a, b, c
    where a.a1=b.b1 and a.a2=c.c2;
QUERY PLAN(text)      
----------------------
Nested Loop(Inner Join)  (cost=8293.46..75282600.44 rows=13743895 width=24)
  Join Filter: ("inner".A2 = "outer".C2)
  ->  Seq Scan on C  (cost=0.00..89.92 rows=8192 width=8)
  ->  Materialize  (cost=8293.46..13287.91 rows=335544 width=16)
        ->  Merge Join(Inner Join)  (cost=1244.80..6318.92 rows=335544 width=16)
              Merge Cond: ("outer".A1 = "inner".B1)
              ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
                    Sort Key: A1
                    ->  Seq Scan on A  (cost=0.00..89.92 rows=8192 width=8)
              ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
                    Sort Key: B1
                    ->  Seq Scan on B  (cost=0.00..89.92 rows=8192 width=8)
总数目:12

--  删除表
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;

use_hj (A , B)

use_hj ::=

  1. 如果A、B都是基表,则表示以A作为外表,B作为内表,两者做hash连接。
  2. 如果A是表集合,B是基表,定义A=(table1, table2, ... ,table n)。此时的语义为:以集合A内各表做连接得到的联接表作为外表,B作为内表,两者做hash连接。(当B是表集合、A是基表时情况类似)
  3. 如果A、B均是表集合,则表示以集合A内各表做连接得到的联接表作为外表,以集合B内各表做连接得到的联接表作为内表,两者做hash连接。

举例:

--  清理环境
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;
DROP TABLE d CASCADE;

--  创建表
CREATE TABLE a(a1 INT, a2 INT);
CREATE TABLE b(b1 INT, b2 INT);
CREATE TABLE c(c1 INT, c2 INT);
CREATE TABLE d(d1 INT, d2 INT);


explain select /*+ use_hj((b,d),(a,c)) */ * from a, b, c, d
    where a.a1=b.b1 and a.a2=c.c2 and b.b2=d.d2;
QUERY PLAN(text)      
----------------------
Hash Join(Inner Join)  (cost=13397.02..19727713.61 rows=562949953 width=32)
  Hash Cond: ("outer".B1 = "inner".A1)
  ->  Merge Join(Inner Join)  (cost=1244.80..6318.92 rows=335544 width=16)
        Merge Cond: ("outer".B2 = "inner".D2)
        ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
              Sort Key: B2
              ->  Seq Scan on B  (cost=0.00..89.92 rows=8192 width=8)
        ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
              Sort Key: D2
              ->  Seq Scan on D  (cost=0.00..89.92 rows=8192 width=8)
  ->  Hash  (cost=6318.92..6318.92 rows=335544 width=16)
        ->  Merge Join(Inner Join)  (cost=1244.80..6318.92 rows=335544 width=16)
              Merge Cond: ("outer".A2 = "inner".C2)
              ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
                    Sort Key: A2
                    ->  Seq Scan on A  (cost=0.00..89.92 rows=8192 width=8)
              ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
                    Sort Key: C2
                    ->  Seq Scan on C  (cost=0.00..89.92 rows=8192 width=8)
总数目:19

--  删除表
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;
DROP TABLE d CASCADE;

use_mj (A , B)

use_mj ::=

  1. 如果A、B都是基表,则表示以A作为外表,B作为内表,两者做merge连接。
  2. 如果A是表集合,B是基表,定义A=(table1, table2, ... ,table n)。此时的语义为:以集合A内各表做连接得到的联接表作为外表,B作为内表,两者做merge连接。(当B是表集合、A是基表时情况类似)
  3. 如果A、B均是表集合,则表示以集合A内各表做连接得到的联接表作为外表,以集合B内各表做连接得到的联接表作为内表,两者做merge连接。

举例:

对于基表a、b、c、d、e、f,用下列一套hint组合可准确指定这六张表的连接方式和顺序:

/*+use_nl((a,b,c,d),(e,f)) use_hj(a,(b,c,d)) use_mj(b,(c,d))
use_nl(c,d) use_nl(e,f)*/

上述hint语句表示的各表连接顺序和方式如下图 21所示:

../../../../../_images/image135.png

图385 hint语义图

use_join (A, B)

use_join ::=

表示在做表连接时,A做外表,B做内表,但不指定具体连接方法。该hint的参数情况与use_nl类似。

如果只是想要指定多表连接的先后顺序,而不指定两表间的连接方法,使用该hint。

举例:

/*+ use_join (d,(a, b,c)) use_join ((a, b),c) use_join (a, b)*/

上述hint表示a做外表b做内表进行连接,然后的到的联结表(a,b)做外表,c做内表进行连接,最后得到的联结表(a,b,c)做内表d做外表进行连接;而所有连接的连接方法(nl、mj或者hj)均由优化器自己选择。

use_semi_nl (A, B)

use_semi_nl ::=

用在父查询中,表明A做外表,B做内表,两者做nestloop连接,连接方式为semi-join。

举例:

--  清理环境
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;

--  创建表
CREATE TABLE a(a1 INT, a2 INT);
CREATE TABLE b(b1 INT, b2 INT);


explain select /*+ use_semi_nl(a,b@sel$2)*/ * from a where a.a1 in (
    select b1 from b);
QUERY PLAN(text)      
----------------------
Nested Loop(Left Semi Join)  (cost=0.00..38643.87 rows=8192 width=8)
  Join Filter: ("outer".A1 = "inner".B1)
  ->  Seq Scan on A  (cost=0.00..89.92 rows=8192 width=8)
  ->  Seq Scan on B  (cost=0.00..89.92 rows=8192 width=4)
总数目:4

--  删除表
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;

use_semi_hj (A, B)

use_semi_hj ::=

用在父查询中,表明A做外表,B做内表,两者做hash join连接,连接方式为semi-join。

举例:

--  清理环境
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;

--  创建表
CREATE TABLE a(a1 INT, a2 INT);
CREATE TABLE b(b1 INT, b2 INT);
CREATE TABLE c(c1 INT, c2 INT);


explain select /*+ use_semi_hj(a,(b@sel$2,c@sel$2))*/ * from a where a.a1 in (
    select b1 from b,c where b.b1=c.c1 and c.c2<10);
QUERY PLAN(text)      
----------------------
Hash Join(Left Semi Join)  (cost=3978.13..4375.25 rows=8192 width=8)
  Hash Cond: ("outer".A1 = "inner".B1)
  ->  Seq Scan on A  (cost=0.00..89.92 rows=8192 width=8)
  ->  Hash  (cost=2580.03..2580.03 rows=111848 width=4)
        ->  Merge Join(Inner Join)  (cost=888.65..2580.03 rows=111848 width=4)
              Merge Cond: ("outer".C1 = "inner".B1)
              ->  Sort  (cost=266.25..273.08 rows=2731 width=4)
                    Sort Key: C1
                    ->  Seq Scan on C  (cost=0.00..110.40 rows=2731 width=4)
                          Scan Key: (C2 < 10)
              ->  Sort  (cost=622.40..642.88 rows=8192 width=4)
                    Sort Key: B1
                    ->  Seq Scan on B  (cost=0.00..89.92 rows=8192 width=4)
总数目:13

--  删除表
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;

use_semi_mj (A, B)

use_semi_mj ::=

用在父查询中,表明A做外表,B做内表,两者做merge join连接,连接方式为semi-join。

举例:

--  清理环境
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;
DROP TABLE d CASCADE;

--  创建表
CREATE TABLE a(a1 INT, a2 INT);
CREATE TABLE b(b1 INT, b2 INT);
CREATE TABLE c(c1 INT, c2 INT);
CREATE TABLE d(d1 INT, d2 INT);


explain select /*+ use_semi_mj((a,b),(c@sel$2,d@sel$2))*/ * from a,b where a.a1=b.b1 and b.b1 in (
    select c2 from c,d where c.c2=d.d2 and d.d1<10);
QUERY PLAN(text)      
----------------------
Merge Join(Left Semi Join)  (cost=2133.45..3318209.62 rows=335544 width=16)
  Merge Cond: ("outer".B1 = "inner".C2)
  ->  Merge Join(Inner Join)  (cost=1244.80..6318.92 rows=335544 width=16)
        Merge Cond: ("outer".A1 = "inner".B1)
        ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
              Sort Key: A1
              ->  Seq Scan on A  (cost=0.00..89.92 rows=8192 width=8)
        ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
              Sort Key: B1
              ->  Seq Scan on B  (cost=0.00..89.92 rows=8192 width=8)
  ->  Merge Join(Inner Join)  (cost=888.65..2580.03 rows=111848 width=4)
        Merge Cond: ("outer".D2 = "inner".C2)
        ->  Sort  (cost=266.25..273.08 rows=2731 width=4)
              Sort Key: D2
              ->  Seq Scan on D  (cost=0.00..110.40 rows=2731 width=4)
                    Scan Key: (D1 < 10)
        ->  Sort  (cost=622.40..642.88 rows=8192 width=4)
              Sort Key: C2
              ->  Seq Scan on C  (cost=0.00..89.92 rows=8192 width=4)
总数目:19

--  删除表
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;
DROP TABLE d CASCADE;

use_nl_with_material (A, B)

use_nl_with_material ::=

表明A做外表,B做内表,两者做nestloop连接,并且采用material计划作为内表扫描计划,内外表做连接的jointype类型由优化器自己决定。

举例:

--  清理环境
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;

--  创建表
CREATE TABLE a(a1 INT, a2 INT);
CREATE TABLE b(b1 INT, b2 INT);
CREATE TABLE c(c1 INT, c2 INT);


explain select /*+use_nl_with_material(a,(b,c))*/ * from a, b, c
    where a.a1=b.b1 and b.b1=c.c1;
QUERY PLAN(text)      
----------------------
Nested Loop(Inner Join)  (cost=8293.46..75282600.44 rows=13743895 width=24)
  Join Filter: ("outer".A1 = "inner".B1)
  ->  Seq Scan on A  (cost=0.00..89.92 rows=8192 width=8)
  ->  Materialize  (cost=8293.46..13287.91 rows=335544 width=16)
        ->  Merge Join(Inner Join)  (cost=1244.80..6318.92 rows=335544 width=16)
              Merge Cond: ("outer".B1 = "inner".C1)
              ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
                    Sort Key: B1
                    ->  Seq Scan on B  (cost=0.00..89.92 rows=8192 width=8)
              ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
                    Sort Key: C1
                    ->  Seq Scan on C  (cost=0.00..89.92 rows=8192 width=8)
总数目:12

--  删除表
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;

use_semi_nl_with_material(A, B)

use_semi_nl_with_material ::=

表明A做外表,B做内表,两者做nestloop连接,并且采用material计划作为内表扫描计划,内外表做连接的jointype类型为semi类型。

举例:

--  清理环境
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;

--  创建表
CREATE TABLE a(a1 INT, a2 INT);
CREATE TABLE b(b1 INT, b2 INT);
CREATE TABLE c(c1 INT, c2 INT);


explain select /*+ use_semi_nl_with_material((a,b),c_alias@sel$2) */ * from a, b, c
    where a.a1=b.b1 and b.b1 in (select c1 from c c_alias where c_alias.c2>6);
QUERY PLAN(text)      
----------------------
Nested Loop(Inner Join)  (cost=1456.04..18929237.59 rows=920840988 width=24)
  ->  Nested Loop(Left Semi Join)  (cost=1357.93..512266.24 rows=112407 width=16)
        Join Filter: ("outer".B1 = "inner".C1)
        ->  Merge Join(Inner Join)  (cost=1244.80..6318.92 rows=335544 width=16)
              Merge Cond: ("outer".A1 = "inner".B1)
              ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
                    Sort Key: A1
                    ->  Seq Scan on A  (cost=0.00..89.92 rows=8192 width=8)
              ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
                    Sort Key: B1
                    ->  Seq Scan on B  (cost=0.00..89.92 rows=8192 width=8)
        ->  Materialize  (cost=113.13..140.44 rows=2731 width=4)
              ->  Seq Scan on C C_ALIAS  (cost=0.00..110.40 rows=2731 width=4)
                    Scan Key: (C2 > 6)
  ->  Materialize  (cost=98.11..180.03 rows=8192 width=8)
        ->  Seq Scan on C  (cost=0.00..89.92 rows=8192 width=8)
总数目:16

--  删除表
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;

use_norm_nl_with_material(A, B)

use_norm_nl_with_material ::=

表明A做外表,B做内表,两者做nestloop连接,并且采用material计划作为内表扫描计划,内外表做连接的jointype类型不是semi类型。

举例:

--  清理环境
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;

--  创建表
CREATE TABLE a(a1 INT, a2 INT);
CREATE TABLE b(b1 INT, b2 INT);
CREATE TABLE c(c1 INT, c2 INT);


explain select /*+use_norm_nl_with_material(a,(b,c))*/ * from a, b, c
    where a.a1=b.b1 and b.b1=c.c1;
QUERY PLAN(text)      
----------------------
Nested Loop(Inner Join)  (cost=8293.46..75282600.44 rows=13743895 width=24)
  Join Filter: ("outer".A1 = "inner".B1)
  ->  Seq Scan on A  (cost=0.00..89.92 rows=8192 width=8)
  ->  Materialize  (cost=8293.46..13287.91 rows=335544 width=16)
        ->  Merge Join(Inner Join)  (cost=1244.80..6318.92 rows=335544 width=16)
              Merge Cond: ("outer".B1 = "inner".C1)
              ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
                    Sort Key: B1
                    ->  Seq Scan on B  (cost=0.00..89.92 rows=8192 width=8)
              ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
                    Sort Key: C1
                    ->  Seq Scan on C  (cost=0.00..89.92 rows=8192 width=8)
总数目:12

--  删除表
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;

use_nl_with_index(A, b index_name)

use_nl_with_index ::=

注解

参数b只能是单表,不能是表集合,表名和索引名之间用空格分隔,该hint必须指定且只能指定一个索引名。 注意该hint与单表的index(a,[ index_1, … , index_n ])的不同。

表明A做外表,b做内表,两者做nestloop连接,并且内表条件下降,扫描采用指定索引,内外表做连接的jointype类型由优化器自己决定。

举例:

--  清理环境
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;

--  创建表
CREATE TABLE a(a1 INT, a2 INT);
CREATE TABLE b(b1 INT, b2 INT);
CREATE TABLE c(c1 INT, c2 INT);
CREATE INDEX c2_index ON c(c2);


explain select /*+use_nl_with_index((a,b),c c2_index)*/ * from a, b, c
    where a.a1=b.b1 and b.b2=c.c2;
QUERY PLAN(text)      
----------------------
Nested Loop(Inner Join)  (cost=1244.80..652418.47 rows=13743895 width=24)
  ->  Merge Join(Inner Join)  (cost=1244.80..6318.92 rows=335544 width=16)
        Merge Cond: ("outer".A1 = "inner".B1)
        ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
              Sort Key: A1
              ->  Seq Scan on A  (cost=0.00..89.92 rows=8192 width=8)
        ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
              Sort Key: B1
              ->  Seq Scan on B  (cost=0.00..89.92 rows=8192 width=8)
  ->  Index Scan using C2_INDEX(Normal Index Scan) on C  (cost=0.00..1.41 rows=41 width=8)
        Index Key: (C.C2 = "outer".B2)
总数目:11

--  删除表
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;

对于该hint的实现,将largs用来存储A,用rargs来存储b和索引。在process_single_table中传入rargs就可以保证原来hint的单表处理函数process_singletable_hints(Query *root, RelOptInfo *rel)的函数接口不变了。

use_norm_nl_with_index(A, b index_name)

use_norm_nl_with_index ::=

表明A做外表,b做内表,两者做nestloop连接,并且内表条件下降,扫描采用指定索引,内外表做连接的jointype类型不是semi类型。

举例:

--  清理环境
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;

--  创建表
CREATE TABLE a(a1 INT, a2 INT);
CREATE TABLE b(b1 INT, b2 INT);
CREATE TABLE c(c1 INT, c2 INT);
CREATE INDEX c2_index ON c(c2);


explain select /*+use_norm_nl_with_index((a,b),c c2_index)*/ * from a, b, c
    where a.a1=b.b1 and b.b2=c.c2;
QUERY PLAN(text)      
----------------------
Nested Loop(Inner Join)  (cost=1244.80..652418.47 rows=13743895 width=24)
  ->  Merge Join(Inner Join)  (cost=1244.80..6318.92 rows=335544 width=16)
        Merge Cond: ("outer".A1 = "inner".B1)
        ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
              Sort Key: A1
              ->  Seq Scan on A  (cost=0.00..89.92 rows=8192 width=8)
        ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
              Sort Key: B1
              ->  Seq Scan on B  (cost=0.00..89.92 rows=8192 width=8)
  ->  Index Scan using C2_INDEX(Normal Index Scan) on C  (cost=0.00..1.41 rows=41 width=8)
        Index Key: (C.C2 = "outer".B2)
总数目:11

--  删除表
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;

use_semi_nl_with_index(A, b index_name)

use_semi_nl_with_index ::=

表明A做外表,b做内表,两者做nestloop连接,并且内表条件下降,扫描采用指定索引,内外表做连接的jointype类型为semi类型。

举例:

--  清理环境
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;

--  创建表
CREATE TABLE a(a1 INT, a2 INT);
CREATE TABLE b(b1 INT, b2 INT);
CREATE TABLE c(c1 INT, c2 INT);
CREATE INDEX c1_index ON c(c1);


explain select /*+ use_semi_nl_with_index((a,b) , c_alias@sel$2 c1_index ) */ * from a, b, c
    where a.a1=b.b1 and b.b1 in (select c1 from c c_alias where c_alias.c2>6);
QUERY PLAN(text)      
----------------------
Nested Loop(Inner Join)  (cost=1342.91..18437176.78 rows=920840988 width=24)
  ->  Nested Loop(Left Semi Join)  (cost=1244.80..20205.43 rows=112407 width=16)
        ->  Merge Join(Inner Join)  (cost=1244.80..6318.92 rows=335544 width=16)
              Merge Cond: ("outer".A1 = "inner".B1)
              ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
                    Sort Key: A1
                    ->  Seq Scan on A  (cost=0.00..89.92 rows=8192 width=8)
              ->  Sort  (cost=622.40..642.88 rows=8192 width=8)
                    Sort Key: B1
                    ->  Seq Scan on B  (cost=0.00..89.92 rows=8192 width=8)
        ->  Index Scan using C1_INDEX(Normal Index Scan) on C C_ALIAS  (cost=0.00..1.52 rows=14 width=4)
              Index Key: (C_ALIAS.C1 = "outer".B1)
              Table Filter: (C2 > 6)
  ->  Materialize  (cost=98.11..180.03 rows=8192 width=8)
        ->  Seq Scan on C  (cost=0.00..89.92 rows=8192 width=8)
总数目:15

--  删除表
DROP TABLE a CASCADE;
DROP TABLE b CASCADE;
DROP TABLE c CASCADE;