[20180713]关于hash join 测试中一个疑问.txt
--//上个星期做的测试,链接: http://blog.itpub.net/267265/viewspace-2157424/--//前几天在家里12c上重复测试,才发现自己没注意细节问题.1.环境:SCOTT@test01p> @ ver1PORT_STRING VERSION BANNER CON_ID------------------------------ -------------- -------------------------------------------------------------------------------- ----------IBMPC/WIN_NT64-9.1.0 12.1.0.1.0 Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production 0create table t1 as select level id ,'t1'||to_char(level) name from dual connect by level<=4;create table t2 as select level+1 id ,'t2'||to_char(level) name from dual connect by level<=4;insert into t1 values (null,'t1null');insert into t2 values (null,'t2null');commit ;--//分析略.insert into t2 select rownum+4 ,'t2'||to_char(rownum+4) from dual connect by level<=10000;commit;SCOTT@test01p> select rowid,t2.* from t2 where id<=4 or id is null;ROWID ID NAME------------------ ---------- --------------------AAAaT5AAJAAAADLAAA 2 t21AAAaT5AAJAAAADLAAB 3 t22AAAaT5AAJAAAADLAAC 4 t23AAAaT5AAJAAAADOAAA t2null--//我自己一直以为执行insert into t2 values (null,'t2null');应该插入的数据块与id=2的数据块一样,实际情况不同.SCOTT@test01p> @ rowid AAAaT5AAJAAAADLAAA OBJECT FILE BLOCK ROW ROWID_DBA DBA TEXT---------- ---------- ---------- ---------- -------------------- -------------------- ---------------------------------------- 107769 9 203 0 0x24000CB 9,203 alter system dump datafile 9 block 203 ;SCOTT@test01p> @ rowid AAAaT5AAJAAAADOAAA OBJECT FILE BLOCK ROW ROWID_DBA DBA TEXT---------- ---------- ---------- ---------- -------------------- -------------------- ---------------------------------------- 107769 9 206 0 0x24000CE 9,206 alter system dump datafile 9 block 206 ;--//实际上ctas插入的第一块紧接着表段HEADER_BLOCK.SCOTT@test01p> select SEGMENT_NAME,SEGMENT_TYPE,HEADER_FILE,HEADER_BLOCK from dba_segments where owner=user and segment_name='T2';SEGMENT_NAME SEGMENT_TYPE HEADER_FILE HEADER_BLOCK-------------------- -------------------- ----------- ------------T2 TABLE 9 2022.这样就很好解析我前面遇到的情况:SCOTT@test01p> alter session set statistics_level=all;Session altered.SCOTT@test01p> select * from t1 where id not in (select id from t2 ) and id is not null;no rows selectedSCOTT@test01p> @ dpc '' ''PLAN_TABLE_OUTPUT-------------------------------------SQL_ID 86bz316n141w9, child number 0-------------------------------------select * from t1 where id not in (select id from t2 ) and id is not nullPlan hash value: 1275484728------------------------------------------------------------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |------------------------------------------------------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | | 14 (100)| | 0 |00:00:00.01 | 14 | | | ||* 1 | HASH JOIN ANTI NA | | 1 | 1 | 12 | 14 (0)| 00:00:01 | 0 |00:00:00.01 | 14 | 1888K| 1888K| 1090K (0)||* 2 | TABLE ACCESS FULL| T1 | 1 | 4 | 32 | 4 (0)| 00:00:01 | 4 |00:00:00.01 | 7 | | | || 3 | TABLE ACCESS FULL| T2 | 1 | 10005 | 40020 | 10 (0)| 00:00:01 | 956 |00:00:00.01 | 7 | | | |--------------------------------------------------------------------------------------------------------------------------------------------------//表T2做全表扫描buffers=7.而实际全表扫描逻辑读31.而且实际读T2记录数是956.SCOTT@test01p> select count(*) from t2 ; COUNT(*)---------- 10005SCOTT@test01p> @ dpc '' ''PLAN_TABLE_OUTPUT-------------------------------------SQL_ID 34jwra7jk76u5, child number 0-------------------------------------select count(*) from t2Plan hash value: 3321871023-------------------------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |-------------------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | 10 (100)| | 1 |00:00:00.01 | 31 || 1 | SORT AGGREGATE | | 1 | 1 | | | 1 |00:00:00.01 | 31 || 2 | TABLE ACCESS FULL| T2 | 1 | 10005 | 10 (0)| 00:00:01 | 10005 |00:00:00.01 | 31 |-------------------------------------------------------------------------------------------------------------SCOTT@test01p> select count(*) from t2 where DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid) between 203 and 205; COUNT(*)---------- 955--//这样扫描dba=9,203到9,205的记录数是955,加上dba=9.206第1条记录是id is NULL,因为存在Null 记录,查询就停止扫描T2.--//而如果交换表连接顺序:SCOTT@test01p> select /*+ SWAP_JOIN_INPUTS(@"SEL$5DA710D3" "T2"@"SEL$2") */ * from t1 where id not in (select id from t2 ) ;no rows selectedSCOTT@test01p> @ dpc '' ''PLAN_TABLE_OUTPUT-------------------------------------SQL_ID aqy7dusnfb5gm, child number 0-------------------------------------select /*+ SWAP_JOIN_INPUTS(@"SEL$5DA710D3" "T2"@"SEL$2") */ * from t1where id not in (select id from t2 )Plan hash value: 2739594415-----------------------------------------------------------------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |-----------------------------------------------------------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | | 14 (100)| | 0 |00:00:00.01 | 7 | | | ||* 1 | HASH JOIN RIGHT ANTI NA| | 1 | 2 | 24 | 14 (0)| 00:00:01 | 0 |00:00:00.01 | 7 | 1753K| 1753K| 1482K (0)|| 2 | TABLE ACCESS FULL | T2 | 1 | 10005 | 40020 | 10 (0)| 00:00:01 | 956 |00:00:00.01 | 7 | | | || 3 | TABLE ACCESS FULL | T1 | 0 | 5 | 40 | 4 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |-----------------------------------------------------------------------------------------------------------------------------------------------------Query Block Name / Object Alias (identified by operation id):------------------------------------------------------------- 1 - SEL$5DA710D3 2 - SEL$5DA710D3 / T2@SEL$2 3 - SEL$5DA710D3 / T1@SEL$1Predicate Information (identified by operation id):--------------------------------------------------- 1 - access("ID"="ID")--//这样T2表扫描到id is null时就停止.而T1表根本不做全表扫描操作.starts=0.