Oracle TABLE ACCESS BY INDEX ROWID

一. 測試環境
SQL> select * from v$version where rownum=1;

BANNER


Oracle Database 11g Enterprise Edition Release11.2.0.3.0 - 64bit Production

SQL> create table dave as selectobject_id,object_name,object_type,created,timestamp,status from all_objects;

表已創建。

SQL> create table dave2 as select * from dave;

表已創建。

–收集統計信息,這裏沒有收集直方圖:

SQL> exec dbms_stats.gather_table_stats(ownname=>‘SYS’,tabname =>‘DAVE’,estimate_percent => 10 ,method_opt =>‘FORCOLUMNS size 1’,degree=>10,cascade => true);

PL/SQL 過程已成功完成。

SQL> exec dbms_stats.gather_table_stats(ownname=>‘SYS’,tabname =>‘DAVE2’,estimate_percent => 10 ,method_opt =>‘FORCOLUMNS size 1’,degree=>10,cascade => true);

PL/SQL 過程已成功完成。

–避免其他影響,先刷新buffer cache:

SQL> alter system flush buffer_cache;

系統已更改。

–查看全表掃描時的執行計劃:

SQL> set autot traceonly

SQL> select d1.object_name,d2.object_type fromdave d1,dave2 d2 where d1.object_id=d2.object_id;

已選擇72762行。

執行計劃


Plan hash value: 3613449503


| Id |Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |


| 0 |SELECT STATEMENT | | 72520 | 3824K| | 695 (1)| 00:00:09 |

|* 1 | HASH JOIN | | 72520 | 3824K| 2536K| 695 (1)| 00:00:09 |

| 2 | TABLE ACCESS FULL| DAVE2 | 71990 | 1687K| | 213 (1)| 00:00:03 |

| 3 | TABLE ACCESS FULL| DAVE | 72520 | 2124K| | 213 (1)| 00:00:03 |


Predicate Information (identified by operation id):


1 -access(“D1”.“OBJECT_ID”=“D2”.“OBJECT_ID”)

統計信息


     0  recursive calls

     0  db block gets

  6353  consistent gets

   1558  physical reads

     0  redo size

3388939 bytes sent via SQL*Net toclient

 53874  bytes received via SQL*Netfrom client

  4852  SQL*Net roundtrips to/fromclient

     0  sorts (memory)

     0  sorts (disk)

 72762  rows processed

–這裏產生了1558的物理讀

SQL>

–在object_id上創建索引:

SQL> create index idx_dave_object_idon dave(object_id);

索引已創建。

SQL> create index idx_dave_object_id2 ondave2(object_id);

索引已創建。

–在次查看執行計劃:

SQL> select d1.object_name,d2.object_type fromdave d1,dave2 d2 where d1.object_id=d2.object_id;

已選擇72762行。

執行計劃


Plan hash value: 3613449503


| Id |Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |


| 0 |SELECT STATEMENT | | 72520 | 3824K| | 695 (1)| 00:00:09 |

|* 1 | HASH JOIN | | 72520 | 3824K| 2536K| 695 (1)| 00:00:09 |

| 2 | TABLE ACCESS FULL| DAVE2 | 71990 | 1687K| | 213 (1)| 00:00:03 |

| 3 | TABLE ACCESS FULL| DAVE | 72520 | 2124K| | 213 (1)| 00:00:03 |


Predicate Information (identified by operation id):


1 -access(“D1”.“OBJECT_ID”=“D2”.“OBJECT_ID”)

統計信息


     1  recursive calls

     0  db block gets

  6353  consistent gets

      0  physical reads

     0  redo size

3388939 bytes sent via SQL*Net toclient

 53874  bytes received via SQL*Netfrom client

  4852  SQL*Net roundtrips to/fromclient

     0  sorts (memory)

     0  sorts (disk)

 72762  rows processed

這裏的物理讀爲0. 但是還是走的是全表掃描。

–刷新一下buffer,增加索引條件:

SQL> alter system flush buffer_cache;

系統已更改。

SQL> select d1.object_name,d2.object_type fromdave d1,dave2 d2 where d1.object_id=d2.object_id and d1.object_id <100;

已選擇98行。

執行計劃


Plan hash value: 504164237


| Id |Operation | Name | Rows | Bytes | Cost (%CPU)| Time |


| 0 |SELECT STATEMENT | | 3600 | 189K| 23 (5)| 00:00:01 |

|* 1 | HASH JOIN | | 3600 | 189K| 23 (5)| 00:00:01 |

| 2 | TABLE ACCESS BY INDEX ROWID| DAVE2 | 3600 | 86400 | 11 (0)| 00:00:01 |

|* 3 | INDEX RANGE SCAN | IDX_DAVE_OBJECT_ID2 | 648 | | 3 (0)| 00:00:01 |

| 4 | TABLE ACCESS BY INDEX ROWID| DAVE | 3626 | 106K| 11 (0)| 00:00:01 |

|* 5 | INDEX RANGE SCAN | IDX_DAVE_OBJECT_ID | 653| | 3 (0)| 00:00:01 |


Predicate Information (identified by operation id):


1 -access(“D1”.“OBJECT_ID”=“D2”.“OBJECT_ID”)

3 -access(“D2”.“OBJECT_ID”<100)

5 -access(“D1”.“OBJECT_ID”<100)

統計信息


     1  recursive calls

     0  db block gets

    20  consistent gets

     6  physical reads

     0  redo size

  3317  bytes sent via SQL*Net toclient

   590  bytes received via SQL*Netfrom client

     8  SQL*Net roundtrips to/fromclient

     0  sorts (memory)

     0  sorts (disk)

    98  rows processed

SQL>

走索引之後,物理讀從1558降到6.

二.說明
在上面的測試中,我們看到了索引掃描的類型和多表關聯的類型,關於這幾種類型的說明,參考:

Oracle 索引掃描的五種類型

http://blog.csdn.net/tianlesoftware/article/details/5852106

多表連接的三種方式詳解 HASH JOIN MERGE JOINNESTED LOOP

http://blog.csdn.net/tianlesoftware/article/details/5826546

從執行計劃中,當我們走索引之後,在對應的表上就會出現:

TABLE ACCESS BY INDEX ROWID

在如下文章中對OracleROWID 有說明。

Oracle Rowid 介紹

http://blog.csdn.net/tianlesoftware/article/details/5020718

rowid是僞列(pseudocolumn),在查詢結果輸出時它被構造出來的。rowid並不會真正存在於表的data block中,其存在於index當中,用來通過rowid來尋找表中的行數據。

ROWID 由以下幾部分組成:

  1. 數據對象編號:每個數據對象(如表或索引)在創建時都分配有此編號,並且此編號在數據庫中是唯一的

  2. 相關文件編號:此編號對於表空間中的每個數據文件是唯一的

  3. 塊編號:表示包含此行的塊在數據文件中的位置

  4. 行編號:標識塊頭中行目錄位置的位置

Oracle 索引中保存的是我們字段的值和該值對應的rowid,我們根據索引進行查找時,就會返回該block的rowid,然後根據rowid直接去block上去我們需要的數據,因此就出現了:

TABLE ACCESS BY INDEX ROWID

因爲ROWID 對應一個block,所以當使用TABLE ACCESS BY INDEX ROWID時,每次就只能讀取一個block。

假設我們我們的數據返回100個ROWID,其中10個row 位於同一個block上,那麼我們只需要訪問91次block,就可以拿到我們需要的數據。

關於如何確定row記錄在哪個block的方法參考:

Oracle rdba和 dba 說明

http://blog.csdn.net/tianlesoftware/article/details/6529346

小結:

(1) TABLE ACCESS BY INDEX ROWID 只出現在使用索引的情況下。

(2) TABLE ACCESS BY INDEX ROWID 是單塊讀,每次只能讀取一個block

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章