[20180713]關於hash join 測試中一個疑問.txt

lfree發表於2018-07-13

[20180713]關於hash join 測試中一個疑問.txt

--//上個星期做的測試,連結: http://blog.itpub.net/267265/viewspace-2157424/
--//前幾天在家裡12c上重複測試,才發現自己沒注意細節問題.

1.環境:
SCOTT@test01p> @ ver1
PORT_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              0

create 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 t21
AAAaT5AAJAAAADLAAB          3 t22
AAAaT5AAJAAAADLAAC          4 t23
AAAaT5AAJAAAADOAAA            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          202

2.這樣就很好解析我前面遇到的情況:
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 selected

SCOTT@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 null
Plan 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(*)
----------
     10005

SCOTT@test01p> @ dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  34jwra7jk76u5, child number 0
-------------------------------------
select count(*) from t2
Plan 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 selected

SCOTT@test01p> @ dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  aqy7dusnfb5gm, child number 0
-------------------------------------
select /*+ SWAP_JOIN_INPUTS(@"SEL$5DA710D3" "T2"@"SEL$2") */ * from t1
where 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$1
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("ID"="ID")
--//這樣T2表掃描到id is null時就停止.而T1表根本不做全表掃描操作.starts=0.

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/267265/viewspace-2157857/,如需轉載,請註明出處,否則將追究法律責任。

相關文章