[20180410]為什麼2個邏輯讀不一樣.txt

lfree發表於2018-04-10

[20180410]為什麼2個邏輯讀不一樣.txt

--//昨天做測試時,發現一個小問題,連結http://blog.itpub.net/267265/viewspace-2152693/
--//發現2個邏輯讀不一樣,做一些簡單探究.

1.環境:
SCOTT@book> @ &r/ver1
PORT_STRING                    VERSION        BANNER
------------------------------ -------------- --------------------------------------------------------------------------------
x86_64/Linux 2.4.xx            11.2.0.4.0     Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

SCOTT@book> create table t1 as select * from all_objects order by DBMS_RANDOM.random;
Table created.

SCOTT@book> create table t2 as select * from t1 order by DBMS_RANDOM.random;
Table created.

--//分析略.Method_Opt => 'FOR ALL COLUMNS SIZE 1 '

2.建立測試指令碼:
$ cat a3.sql
set term off
select  t2.* from t2 where  exists (select owner from t1 where t1.object_id=t2.object_id );
set term on

--//主要避免顯示輸出在螢幕太亂.

3.測試:

SCOTT@book> alter session set statistics_level=all;
Session altered.

SCOTT@book> show array
arraysize 200


SCOTT@book> @ a3
SCOTT@book> @ &r/dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  7wjwu1wk8vu8q, child number 0
-------------------------------------
select  t2.* from t2 where  exists (select owner from t1 where
t1.object_id=t2.object_id )
Plan hash value: 3761397674
-----------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation            | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |      |      1 |        |       |   677 (100)|          |  84765 |00:00:00.16 |    2849 |   2422 |       |       |          |
|*  1 |  HASH JOIN RIGHT SEMI|      |      1 |  84765 |  8526K|   677   (1)| 00:00:09 |  84765 |00:00:00.16 |    2849 |   2422 |  5236K|  2890K| 5675K (0)|
|   2 |   TABLE ACCESS FULL  | T1   |      1 |  84765 |   413K|   338   (1)| 00:00:05 |  84765 |00:00:00.02 |    1213 |   1211 |       |       |          |
|   3 |   TABLE ACCESS FULL  | T2   |      1 |  84765 |  8112K|   338   (1)| 00:00:05 |  84765 |00:00:00.03 |    1636 |   1211 |       |       |          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$5DA710D3
   2 - SEL$5DA710D3 / T1@SEL$2
   3 - SEL$5DA710D3 / T2@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")

--//你可以發現t1的全表掃描邏輯讀1213,而t2的全表掃描邏輯讀是1636,而2個表實際上大小一樣的.為什麼出現這樣的情況呢?

4.分析:
--//實際上看執行計劃就明白了,T1表作為驅動表,全表掃描T1作為hash雜湊表,而T2查探如果符合條件輸出(受arraay影響)
--//修改array引數就明白了:

SCOTT@book> set array 50
SCOTT@book> @ a3
SCOTT@book> @ &r/dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  7wjwu1wk8vu8q, child number 0
-------------------------------------
select  t2.* from t2 where  exists (select owner from t1 where
t1.object_id=t2.object_id )
Plan hash value: 3761397674
-----------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation            | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |      |      1 |        |       |   677 (100)|          |  84765 |00:00:00.23 |    4107 |   2422 |       |       |          |
|*  1 |  HASH JOIN RIGHT SEMI|      |      1 |  84765 |  8526K|   677   (1)| 00:00:09 |  84765 |00:00:00.23 |    4107 |   2422 |  5236K|  2890K| 5729K (0)|
|   2 |   TABLE ACCESS FULL  | T1   |      1 |  84765 |   413K|   338   (1)| 00:00:05 |  84765 |00:00:00.02 |    1213 |   1211 |       |       |          |
|   3 |   TABLE ACCESS FULL  | T2   |      1 |  84765 |  8112K|   338   (1)| 00:00:05 |  84765 |00:00:00.06 |    2894 |   1211 |       |       |          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------

--//可以發現t1的全表掃描邏輯讀依舊是1213,而t2的全表掃描邏輯讀是2894.
--//實際上對T1的邏輯讀解決T1佔用的塊數.
SCOTT@book> select blocks from dba_tables where owner=user and table_name='T1';
    BLOCKS
----------
      1239

--//再簡單做一個測試就明白了.
SCOTT@book> select /*+ full(t1) */ count(*) from t1;
  COUNT(*)
----------
     84765

SCOTT@book> @ &r/dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  8txmkmay1nwxd, child number 0
-------------------------------------
select /*+ full(t1) */ count(*) from t1
Plan hash value: 3724264953
----------------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |
----------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |   338 (100)|          |      1 |00:00:00.03 |    1213 |   1211 |
|   1 |  SORT AGGREGATE    |      |      1 |      1 |            |          |      1 |00:00:00.03 |    1213 |   1211 |
|   2 |   TABLE ACCESS FULL| T1   |      1 |  84765 |   338   (1)| 00:00:05 |  84765 |00:00:00.02 |    1213 |   1211 |
----------------------------------------------------------------------------------------------------------------------

--//count(*)記數,全表掃描邏輯讀是1213.與前面符合.

$ cat a2.sql
set term off
select /*+ full(t2) */ owner from t2;
set term on

SCOTT@book> show array
arraysize 50

SCOTT@book> @ a2.sql
SCOTT@book> @ &r/dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  bvvnmu4zqz3pj, child number 0
-------------------------------------
select /*+ full(t2) */ owner from t2
Plan hash value: 1513984157
-----------------------------------------------------------------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |
-----------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |       |   338 (100)|          |  84765 |00:00:00.05 |    2894 |   1211 |
|   1 |  TABLE ACCESS FULL| T2   |      1 |  84765 |   496K|   338   (1)| 00:00:05 |  84765 |00:00:00.05 |    2894 |   1211 |
-----------------------------------------------------------------------------------------------------------------------------

--//邏輯讀是2894,與前面設定array=50一致.

5.補充:
--//別人問的問題,是否可以實現執行如下語句時.
select  t2.* from t2 where  exists (select owner from t1 where t1.object_id=t2.object_id );
--//T2作為驅動表.測試看看.

--//再次執行a3.sql,取出執行計劃outline:
SCOTT@book> @ &r/dpc '' outline
..
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('11.2.0.4')
      DB_VERSION('11.2.0.4')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$5DA710D3")
      UNNEST(@"SEL$2")
      OUTLINE(@"SEL$1")
      OUTLINE(@"SEL$2")
      FULL(@"SEL$5DA710D3" "T2"@"SEL$1")
      FULL(@"SEL$5DA710D3" "T1"@"SEL$2")
      LEADING(@"SEL$5DA710D3" "T2"@"SEL$1" "T1"@"SEL$2")
      USE_HASH(@"SEL$5DA710D3" "T1"@"SEL$2")
      SWAP_JOIN_INPUTS(@"SEL$5DA710D3" "T1"@"SEL$2")
      END_OUTLINE_DATA
  */

--//修改a3.sql指令碼如下,不要SWAP_JOIN_INPUTS行.

$ cat a3.sql
set term off
select
/*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('11.2.0.4')
      DB_VERSION('11.2.0.4')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$5DA710D3")
      UNNEST(@"SEL$2")
      OUTLINE(@"SEL$1")
      OUTLINE(@"SEL$2")
      FULL(@"SEL$5DA710D3" "T2"@"SEL$1")
      FULL(@"SEL$5DA710D3" "T1"@"SEL$2")
      LEADING(@"SEL$5DA710D3" "T2"@"SEL$1" "T1"@"SEL$2")
      USE_HASH(@"SEL$5DA710D3" "T1"@"SEL$2")
      END_OUTLINE_DATA
  */
t2.* from t2 where  exists (select owner from t1 where t1.object_id=t2.object_id );
set term on

SCOTT@book> @ a3.sql
SCOTT@book> @ &r/dpc '' outline
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  2rc0puqy3d5th, child number 0
-------------------------------------
select  /*+       BEGIN_OUTLINE_DATA       IGNORE_OPTIM_EMBEDDED_HINTS
     OPTIMIZER_FEATURES_ENABLE('11.2.0.4')       DB_VERSION('11.2.0.4')
      ALL_ROWS       OUTLINE_LEAF(@"SEL$5DA710D3")
UNNEST(@"SEL$2")       OUTLINE(@"SEL$1")       OUTLINE(@"SEL$2")
FULL(@"SEL$5DA710D3" "T2"@"SEL$1")       FULL(@"SEL$5DA710D3"
"T1"@"SEL$2")       LEADING(@"SEL$5DA710D3" "T2"@"SEL$1" "T1"@"SEL$2")
     USE_HASH(@"SEL$5DA710D3" "T1"@"SEL$2")       END_OUTLINE_DATA   */
t2.* from t2 where  exists (select owner from t1 where
t1.object_id=t2.object_id )

Plan hash value: 3077929639

-----------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |       |       |  1187 (100)|          |  84765 |00:00:00.27 |    4095 |   2422 |       |       |          |
|*  1 |  HASH JOIN SEMI    |      |      1 |  84765 |  8526K|  9112K|  1187   (1)| 00:00:15 |  84765 |00:00:00.27 |    4095 |   2422 |    13M|  2225K|   14M (0)|
|   2 |   TABLE ACCESS FULL| T2   |      1 |  84765 |  8112K|       |   338   (1)| 00:00:05 |  84765 |00:00:00.03 |    1213 |   1211 |       |       |          |
|   3 |   TABLE ACCESS FULL| T1   |      1 |  84765 |   413K|       |   338   (1)| 00:00:05 |  84765 |00:00:00.03 |    2882 |   1211 |       |       |          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------

--//這樣T2作為驅動表.而Id=2變成了HASH JOIN SEMI,而不是HASH JOIN RIGHT SEMI.
--//主要差別實際上在於生成hash表大小,先掃描T1,實際上全表掃描,僅僅需要object_id欄位就ok了,這樣生成的hash表要小.E-Bytes=413K亦可以說明問題.

--//手工寫提示如下,也可以實現:
$ cat a5.sql
set term off
select  /*+ LEADING(T2 T1) USE_HASH(T1) */ t2.* from t2 where  exists (select 1 from t1 where t1.object_id=t2.object_id );
set term on
--//注:我把owner換成1.

SCOTT@book> @ a5.sql
SCOTT@book> @ &r/dpc '' outline
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  7gdpjgm7h1u9j, child number 0
-------------------------------------
select  /*+ LEADING(T2 T1) USE_HASH(T1) */ t2.* from t2 where  exists
(select 1 from t1 where t1.object_id=t2.object_id )

Plan hash value: 3077929639

-----------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |       |       |  1187 (100)|          |  84765 |00:00:00.28 |    4095 |   2422 |       |       |          |
|*  1 |  HASH JOIN SEMI    |      |      1 |  84765 |  8526K|  9112K|  1187   (1)| 00:00:15 |  84765 |00:00:00.28 |    4095 |   2422 |    13M|  2225K|   14M (0)|
|   2 |   TABLE ACCESS FULL| T2   |      1 |  84765 |  8112K|       |   338   (1)| 00:00:05 |  84765 |00:00:00.03 |    1213 |   1211 |       |       |          |
|   3 |   TABLE ACCESS FULL| T1   |      1 |  84765 |   413K|       |   338   (1)| 00:00:05 |  84765 |00:00:00.04 |    2882 |   1211 |       |       |          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------

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

相關文章