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次,被驱动表0次
- 驱动表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