Oracle Hash Join被驱动表被访问0次的另外一种情况

 

Oracle Hash Join被驱动表被访问0次的另外一种情况

 

前言

遇到了这样子的情况,HJ中驱动表满足条件的有大于0行的数据,但是被驱动表却一次都不访问,如下执行计划所示。

-----------------------------------------------------------------------------------------------------------------
| Id  | Operation           | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |      1 |        |      1 |00:00:00.01 |       3 |       |       |          |
|   1 |  SORT AGGREGATE     |      |      1 |      1 |      1 |00:00:00.01 |       3 |       |       |          |
|*  2 |   HASH JOIN         |      |      1 |      1 |      0 |00:00:00.01 |       3 |  1172K|  1172K|  441K (0)|
|*  3 |    TABLE ACCESS FULL| BB   |      1 |      2 |      2 |00:00:00.01 |       3 |       |       |          |
|*  4 |    TABLE ACCESS FULL| AA   |      0 |      2 |      0 |00:00:00.01 |       0 |       |       |          |
-----------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("BB"."NAME"="AA"."NAME")
   3 - filter(("BB"."ID"=3 OR "BB"."ID"=5))
   4 - filter(("AA"."ID"=3 OR "AA"."ID"=5))

id3的A-Rows表示有2行符合条件的数据,但是id4步骤却一次都不执行。

 

HJ表访问次数各种情况

  1. 驱动表1次,被驱动表1次
  2. 驱动表1次,被驱动表0次
  3. 驱动表0次,被驱动表0次

其中,第2种情况有两种原因导致,我们讨论就是其中一种。

 

构造环境

11.2.0.4.0。

aa表和bb表是一样的。

21:14:47 ZKM@test(934)> select * from aa;

        ID NAME
---------- ------------------------------------------------------------
         1 a
         2 b
         3
         4 d
         5
         6 a

6 rows selected.

Elapsed: 00:00:00.00
21:23:18 ZKM@test(934)> select * from bb;

        ID NAME
---------- ------------------------------------------------------------
         1 a
         2 b
         3
         4 d
         5
         6 a

6 rows selected.

Elapsed: 00:00:00.00

 

 

演示情况1

驱动表访问1次,被驱动表访问1次。

21:23:21 ZKM@test(934)> select count(*) from aa,bb where aa.name=bb.name;

  COUNT(*)
----------
         6

Elapsed: 00:00:00.01
21:25:16 ZKM@test(934)> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  2y1sdr2uydju8, child number 0
-------------------------------------
select count(*) from aa,bb where aa.name=bb.name

Plan hash value: 532233124

-----------------------------------------------------------------------------------------------------------------
| Id  | Operation           | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |      1 |        |      1 |00:00:00.01 |       6 |       |       |          |
|   1 |  SORT AGGREGATE     |      |      1 |      1 |      1 |00:00:00.01 |       6 |       |       |          |
|*  2 |   HASH JOIN         |      |      1 |      5 |      6 |00:00:00.01 |       6 |  2616K|  2616K|  840K (0)|
|   3 |    TABLE ACCESS FULL| AA   |      1 |      6 |      6 |00:00:00.01 |       3 |       |       |          |
|   4 |    TABLE ACCESS FULL| BB   |      1 |      6 |      6 |00:00:00.01 |       3 |       |       |          |
-----------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("AA"."NAME"="BB"."NAME")

Note
-----
   - dynamic sampling used for this statement (level=2)


25 rows selected.

Elapsed: 00:00:00.06

 

 

演示情况3

驱动表访问0次,被驱动表访问0次。

21:25:17 ZKM@qadb1(934)> select count(*) from aa,bb where aa.name=bb.name and 1=2;

  COUNT(*)
----------
         0

Elapsed: 00:00:00.00
21:26:40 ZKM@qadb1(934)> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  dy95brx8h9u5b, child number 0
-------------------------------------
select count(*) from aa,bb where aa.name=bb.name and 1=2

Plan hash value: 2229986580

--------------------------------------------------------------------------------------------------------
| Id  | Operation            | Name | Starts | E-Rows | A-Rows |   A-Time   |  OMem |  1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |      |      1 |        |      1 |00:00:00.01 |       |       |          |
|   1 |  SORT AGGREGATE      |      |      1 |      1 |      1 |00:00:00.01 |       |       |          |
|*  2 |   FILTER             |      |      1 |        |      0 |00:00:00.01 |       |       |          |
|*  3 |    HASH JOIN         |      |      0 |      5 |      0 |00:00:00.01 |  1421K|  1421K|          |
|   4 |     TABLE ACCESS FULL| AA   |      0 |      6 |      0 |00:00:00.01 |       |       |          |
|   5 |     TABLE ACCESS FULL| BB   |      0 |      6 |      0 |00:00:00.01 |       |       |          |
--------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter(NULL IS NOT NULL)
   3 - access("AA"."NAME"="BB"."NAME")

Note
-----
   - dynamic sampling used for this statement (level=2)


27 rows selected.

Elapsed: 00:00:00.04

 

 

演示情况2

驱动表访问1次,被驱动表访问0次。

 

其中的一种情况如下,驱动表访问过滤条件后不存在符合条件的数据,如下,id3的A-Rows为0,那么id4步骤就不会再执行了。

21:28:08 ZKM@test(934)> select  count(*) from bb,aa where bb.name=aa.name and aa.id=99;

  COUNT(*)
----------
         0

Elapsed: 00:00:00.01
21:28:16 ZKM@test(934)> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  gdsu06n1bxz5k, child number 0
-------------------------------------
select  count(*) from bb,aa where bb.name=aa.name and aa.id=99

Plan hash value: 532233124

-----------------------------------------------------------------------------------------------------------------
| Id  | Operation           | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |      1 |        |      1 |00:00:00.01 |       3 |       |       |          |
|   1 |  SORT AGGREGATE     |      |      1 |      1 |      1 |00:00:00.01 |       3 |       |       |          |
|*  2 |   HASH JOIN         |      |      1 |      1 |      0 |00:00:00.01 |       3 |  1172K|  1172K|  457K (0)|
|*  3 |    TABLE ACCESS FULL| AA   |      1 |      1 |      0 |00:00:00.01 |       3 |       |       |          |
|   4 |    TABLE ACCESS FULL| BB   |      0 |      6 |      0 |00:00:00.01 |       0 |       |       |          |
-----------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("BB"."NAME"="AA"."NAME")
   3 - filter("AA"."ID"=99)

Note
-----
   - dynamic sampling used for this statement (level=2)


26 rows selected.

Elapsed: 00:00:00.02

 

 

另外一种情况,驱动表过滤后存在符合条件的数据,但是被驱动表仍旧是被访问0次。

如下,id3处的A-Rows表示有2行符合条件数据,但是id4的starts为0,证明被驱动表aa被访问了0次。

21:29:31 ZKM@test(934)> select  count(*) from bb,aa where bb.name=aa.name and bb.id in (3,5) and aa.id in (3,5);

  COUNT(*)
----------
         0

Elapsed: 00:00:00.00
21:32:15 ZKM@test(934)> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  36gd0c4fcp13h, child number 0
-------------------------------------
select  count(*) from bb,aa where bb.name=aa.name and bb.id in (3,5)
and aa.id in (3,5)

Plan hash value: 4233150

-----------------------------------------------------------------------------------------------------------------
| Id  | Operation           | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |      1 |        |      1 |00:00:00.01 |       3 |       |       |          |
|   1 |  SORT AGGREGATE     |      |      1 |      1 |      1 |00:00:00.01 |       3 |       |       |          |
|*  2 |   HASH JOIN         |      |      1 |      1 |      0 |00:00:00.01 |       3 |  1172K|  1172K|  441K (0)|
|*  3 |    TABLE ACCESS FULL| BB   |      1 |      2 |      2 |00:00:00.01 |       3 |       |       |          |
|*  4 |    TABLE ACCESS FULL| AA   |      0 |      2 |      0 |00:00:00.01 |       0 |       |       |          |
-----------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("BB"."NAME"="AA"."NAME")
   3 - filter(("BB"."ID"=3 OR "BB"."ID"=5))
   4 - filter(("AA"."ID"=3 OR "AA"."ID"=5))

Note
-----
   - dynamic sampling used for this statement (level=2)


28 rows selected.

Elapsed: 00:00:00.03

 

 

为什么会出现这种情况,原因是id3处过滤bb表后的两行数据的连接条件的字段name均为空,因此直接hash join去计算的时候明显不会有aa表与之相符合的数据。

21:40:29 ZKM@test(934)> select * from bb where bb.id in (3,5);

        ID NAME
---------- ------------------------------------------------------------
         3
         5

Elapsed: 00:00:00.00

 

 

若把条件改为bb.id in (1,3,5),其中,当bb.id=1时,bb.name不为空,那么即使只有一个不为空的连接条件字段值,被驱动表也会被访问1次。

21:41:19 ZKM@test(934)> select /*+ leading(bb) use_hash(aa) */ count(*) from bb,aa where bb.name=aa.name and bb.id in (1,3,5) and aa.id in (3,5);

  COUNT(*)
----------
         0

Elapsed: 00:00:00.00
21:42:01 ZKM@test(934)> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  2pa4m63zsya7g, child number 0
-------------------------------------
select /*+ leading(bb) use_hash(aa) */ count(*) from bb,aa where
bb.name=aa.name and bb.id in (1,3,5) and aa.id in (3,5)

Plan hash value: 4233150

-----------------------------------------------------------------------------------------------------------------
| Id  | Operation           | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |      1 |        |      1 |00:00:00.01 |       6 |       |       |          |
|   1 |  SORT AGGREGATE     |      |      1 |      1 |      1 |00:00:00.01 |       6 |       |       |          |
|*  2 |   HASH JOIN         |      |      1 |      1 |      0 |00:00:00.01 |       6 |  2616K|  2616K|  680K (0)|
|*  3 |    TABLE ACCESS FULL| BB   |      1 |      3 |      3 |00:00:00.01 |       3 |       |       |          |
|*  4 |    TABLE ACCESS FULL| AA   |      1 |      2 |      2 |00:00:00.01 |       3 |       |       |          |
-----------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("BB"."NAME"="AA"."NAME")
   3 - filter(("BB"."ID"=1 OR "BB"."ID"=3 OR "BB"."ID"=5))
   4 - filter(("AA"."ID"=3 OR "AA"."ID"=5))

Note
-----
   - dynamic sampling used for this statement (level=2)


28 rows selected.

Elapsed: 00:00:00.05

 

posted @ 2021-01-05 21:44  PiscesCanon  阅读(116)  评论(0编辑  收藏  举报