oracle 索引訪問的幾種方式
索引的全掃描跟索引的快速全掃描
索引快速全掃描:從索引段頭開始多塊讀HWM以下的所有根塊、枝塊、葉塊,所以透過FFS讀出來的資料讀取順序是由物理儲存位置決定的、可能是無序的。因此在這類操作中,我們可以看到會話會大量的出現db file scattered read等待。
索引全掃描:索引全掃描是根據葉節點鏈來進行的。進行索引全掃描首先要從根開始,找到葉節點鏈上的第一個資料塊,然後沿著葉節點鏈進行掃描,由於葉節點鏈是根據索引鍵值排序的,因此這樣掃描出來的資料本身就是排序的,資料讀出後不需要再次排序。這種掃描方式和索引快速全掃描相比,首先要找到索引的根,然後透過枝節點找到第一個葉節點,然後再順著葉節點鏈掃描整個索引。索引全掃描的IO成本比索引快速全掃描要大很多,讀取根節點和葉節點的成本相對不大,不過由於順著葉節點鏈掃描整個索引的時候無法使用多塊讀,而只能使用單塊讀,因此這種掃描方式的IO開銷要遠大於索引快速全掃描。這種索引掃描,我們如果對會話進行跟蹤,會發現大量的db file sequential read等待
20:44:29 scott@orcl> create table test as select * from emp;
Table created.
Elapsed: 00:00:00.30
20:44:39 scott@orcl> alter table test add constraint pk_test primary key(empno);
Table altered.
Elapsed: 00:00:00.36
20:45:12 scott@orcl> select * from test;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
------------- ---------- --------- ------------- ------------------- ------------- ------------- -------------
7369 SMITH CLERK 7902 1980-12-17 00:00:00 800 20
7499 ALLEN SALESMAN 7698 1981-02-20 00:00:00 1600 300 30
7521 WARD SALESMAN 7698 1981-02-22 00:00:00 1250 500 30
7566 JONES MANAGER 7839 1981-04-02 00:00:00 2975 20
7654 MARTIN SALESMAN 7698 1981-09-28 00:00:00 1250 1400 30
7698 BLAKE MANAGER 7839 1981-05-01 00:00:00 2850 30
7782 CLARK MANAGER 7839 1981-06-09 00:00:00 2450 10
7788 SCOTT ANALYST 7566 1987-04-19 00:00:00 3000 20
7839 KING PRESIDENT 1981-11-17 00:00:00 5000 10
7844 TURNER SALESMAN 7698 1981-09-08 00:00:00 1500 0 30
7876 ADAMS CLERK 7788 1987-05-23 00:00:00 1100 20
7900 JAMES CLERK 7698 1981-12-03 00:00:00 950 30
7902 FORD ANALYST 7566 1981-12-03 00:00:00 3000 20
7934 MILLER CLERK 7782 1982-01-23 00:00:00 1300 10
14 rows selected.
Elapsed: 00:00:00.01
20:45:22 scott@orcl> create table t as select * from emp where empno=7900;
Table created.
Elapsed: 00:00:00.03
20:46:54 scott@orcl> begin
20:47:00 2 for i in 1..7200 loop
20:47:12 3 update t set empno=i;
20:47:24 4 insert into test select * from t;
20:47:40 5 commit;
20:47:42 6 end loop;
20:47:47 7 end;
20:47:48 8 /
PL/SQL procedure successfully completed.
scott@orcl> select empno from test;
7214 rows selected.
Elapsed: 00:00:00.09
Execution Plan
----------------------------------------------------------
Plan hash value: 850129961
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7214 | 21642 | 8 (0)| 00:00:01 |
| 1 | INDEX FAST FULL SCAN| PK_TEST | 7214 | 21642 | 8 (0)| 00:00:01 |
--------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
509 consistent gets
0 physical reads
0 redo size
125803 bytes sent via SQL*Net to client
5800 bytes received via SQL*Net from client
482 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
7214 rows processed
scott@orcl> select empno from emp;
14 rows selected.
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 179099197
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 56 | 1 (0)| 00:00:01 |
| 1 | INDEX FULL SCAN | PK_EMP | 14 | 56 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
2 consistent gets
0 physical reads
0 redo size
686 bytes sent via SQL*Net to client
520 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
14 rows processed
索引的跳躍式掃描
21:22:06 scott@orcl> select distinct id from test2;
ID
-------------
1
2
21:16:40 scott@orcl> create index idx_test2 on test2(id,empno);
Index created.
21:19:16 scott@orcl> analyze table test2 compute statistics;
Table analyzed.
Elapsed: 00:00:00.10
21:19:24 scott@orcl> select * from test2 where empno=7788;
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 3100316192
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 33 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST2 | 1 | 33 | 4 (0)| 00:00:01 |
|* 2 | INDEX SKIP SCAN | IDX_TEST2 | 1 | | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMPNO"=7788)
filter("EMPNO"=7788)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
6 consistent gets
0 physical reads
0 redo size
1094 bytes sent via SQL*Net to client
519 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
從上面可以看到,在沒有指定前導列的情況下還能夠用上該索引,就是因為orcle幫助我們對該索引的前導列的所有的distinct的值做了個遍歷。
所謂的對目標的distinct的值做了遍歷。其含義就是對目標的sql做了等價的改寫(即把要用的目標索引所有前導列的distinct的值都加進來。我們看到
索引的前導列id的值只有1,2兩個。所以我們就能簡單的理解oracle把
select * from test2 where empno=7788;
改寫成了
select * from test2 where id=1 and empno=7788 union all select * from test2 where id=2 and empno=7788;
所以我們看到 oracle的索引的跳躍式掃描僅僅適用於那些目標的前導列的distinct只數量比較少的情況,後續非前導列的值的選擇性有非常好的情況下。
索引範圍掃描
21:35:15 scott@orcl> select * from test where empno<300;
299 rows selected.
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 115135762
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 272 | 8976 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST | 272 | 8976 | 4 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | PK_TEST | 272 | | 2 (0)| 00:00:01 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMPNO"<300)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
45 consistent gets
0 physical reads
0 redo size
17688 bytes sent via SQL*Net to client
728 bytes received via SQL*Net from client
21 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
299 rows processed
適用於謂詞條件有選擇範圍的
索引快速全掃描:從索引段頭開始多塊讀HWM以下的所有根塊、枝塊、葉塊,所以透過FFS讀出來的資料讀取順序是由物理儲存位置決定的、可能是無序的。因此在這類操作中,我們可以看到會話會大量的出現db file scattered read等待。
索引全掃描:索引全掃描是根據葉節點鏈來進行的。進行索引全掃描首先要從根開始,找到葉節點鏈上的第一個資料塊,然後沿著葉節點鏈進行掃描,由於葉節點鏈是根據索引鍵值排序的,因此這樣掃描出來的資料本身就是排序的,資料讀出後不需要再次排序。這種掃描方式和索引快速全掃描相比,首先要找到索引的根,然後透過枝節點找到第一個葉節點,然後再順著葉節點鏈掃描整個索引。索引全掃描的IO成本比索引快速全掃描要大很多,讀取根節點和葉節點的成本相對不大,不過由於順著葉節點鏈掃描整個索引的時候無法使用多塊讀,而只能使用單塊讀,因此這種掃描方式的IO開銷要遠大於索引快速全掃描。這種索引掃描,我們如果對會話進行跟蹤,會發現大量的db file sequential read等待
20:44:29 scott@orcl> create table test as select * from emp;
Table created.
Elapsed: 00:00:00.30
20:44:39 scott@orcl> alter table test add constraint pk_test primary key(empno);
Table altered.
Elapsed: 00:00:00.36
20:45:12 scott@orcl> select * from test;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
------------- ---------- --------- ------------- ------------------- ------------- ------------- -------------
7369 SMITH CLERK 7902 1980-12-17 00:00:00 800 20
7499 ALLEN SALESMAN 7698 1981-02-20 00:00:00 1600 300 30
7521 WARD SALESMAN 7698 1981-02-22 00:00:00 1250 500 30
7566 JONES MANAGER 7839 1981-04-02 00:00:00 2975 20
7654 MARTIN SALESMAN 7698 1981-09-28 00:00:00 1250 1400 30
7698 BLAKE MANAGER 7839 1981-05-01 00:00:00 2850 30
7782 CLARK MANAGER 7839 1981-06-09 00:00:00 2450 10
7788 SCOTT ANALYST 7566 1987-04-19 00:00:00 3000 20
7839 KING PRESIDENT 1981-11-17 00:00:00 5000 10
7844 TURNER SALESMAN 7698 1981-09-08 00:00:00 1500 0 30
7876 ADAMS CLERK 7788 1987-05-23 00:00:00 1100 20
7900 JAMES CLERK 7698 1981-12-03 00:00:00 950 30
7902 FORD ANALYST 7566 1981-12-03 00:00:00 3000 20
7934 MILLER CLERK 7782 1982-01-23 00:00:00 1300 10
14 rows selected.
Elapsed: 00:00:00.01
20:45:22 scott@orcl> create table t as select * from emp where empno=7900;
Table created.
Elapsed: 00:00:00.03
20:46:54 scott@orcl> begin
20:47:00 2 for i in 1..7200 loop
20:47:12 3 update t set empno=i;
20:47:24 4 insert into test select * from t;
20:47:40 5 commit;
20:47:42 6 end loop;
20:47:47 7 end;
20:47:48 8 /
PL/SQL procedure successfully completed.
scott@orcl> select empno from test;
7214 rows selected.
Elapsed: 00:00:00.09
Execution Plan
----------------------------------------------------------
Plan hash value: 850129961
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7214 | 21642 | 8 (0)| 00:00:01 |
| 1 | INDEX FAST FULL SCAN| PK_TEST | 7214 | 21642 | 8 (0)| 00:00:01 |
--------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
509 consistent gets
0 physical reads
0 redo size
125803 bytes sent via SQL*Net to client
5800 bytes received via SQL*Net from client
482 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
7214 rows processed
scott@orcl> select empno from emp;
14 rows selected.
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 179099197
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 56 | 1 (0)| 00:00:01 |
| 1 | INDEX FULL SCAN | PK_EMP | 14 | 56 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
2 consistent gets
0 physical reads
0 redo size
686 bytes sent via SQL*Net to client
520 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
14 rows processed
索引的跳躍式掃描
21:22:06 scott@orcl> select distinct id from test2;
ID
-------------
1
2
21:16:40 scott@orcl> create index idx_test2 on test2(id,empno);
Index created.
21:19:16 scott@orcl> analyze table test2 compute statistics;
Table analyzed.
Elapsed: 00:00:00.10
21:19:24 scott@orcl> select * from test2 where empno=7788;
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 3100316192
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 33 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST2 | 1 | 33 | 4 (0)| 00:00:01 |
|* 2 | INDEX SKIP SCAN | IDX_TEST2 | 1 | | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMPNO"=7788)
filter("EMPNO"=7788)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
6 consistent gets
0 physical reads
0 redo size
1094 bytes sent via SQL*Net to client
519 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
從上面可以看到,在沒有指定前導列的情況下還能夠用上該索引,就是因為orcle幫助我們對該索引的前導列的所有的distinct的值做了個遍歷。
所謂的對目標的distinct的值做了遍歷。其含義就是對目標的sql做了等價的改寫(即把要用的目標索引所有前導列的distinct的值都加進來。我們看到
索引的前導列id的值只有1,2兩個。所以我們就能簡單的理解oracle把
select * from test2 where empno=7788;
改寫成了
select * from test2 where id=1 and empno=7788 union all select * from test2 where id=2 and empno=7788;
所以我們看到 oracle的索引的跳躍式掃描僅僅適用於那些目標的前導列的distinct只數量比較少的情況,後續非前導列的值的選擇性有非常好的情況下。
索引範圍掃描
21:35:15 scott@orcl> select * from test where empno<300;
299 rows selected.
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 115135762
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 272 | 8976 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST | 272 | 8976 | 4 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | PK_TEST | 272 | | 2 (0)| 00:00:01 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMPNO"<300)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
45 consistent gets
0 physical reads
0 redo size
17688 bytes sent via SQL*Net to client
728 bytes received via SQL*Net from client
21 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
299 rows processed
適用於謂詞條件有選擇範圍的
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/25462274/viewspace-2124998/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Oracle 索引訪問方式Oracle索引
- 資料庫訪問幾種方式對比資料庫
- 常見SQL訪問索引的方式SQL索引
- oracle 索引和不走索引的幾種形式Oracle索引
- Oracle訪問表的方式Oracle
- 執行計劃-資料訪問方式(全表掃描與4種索引的方式)索引
- Oracle 表訪問方式Oracle
- oracle表訪問方式Oracle
- Python訪問Oracle的兩種資料獲取方式PythonOracle
- 【oracle】index的幾種掃描方式OracleIndex
- c#訪問oracle幾種方法(轉載)_data accessC#Oracle
- 訪問資料庫的幾種方法資料庫
- Oracle指令碼(Oracle Scripts) – 檢視索引訪問次數及索引訪問型別Oracle指令碼索引型別
- [zt] Oracle不使用索引的幾種情況Oracle索引
- smarty中三種變數的訪問方式變數
- Oracle訪問索引的執行計劃(一)Oracle索引
- Oracle訪問索引的執行計劃(二)Oracle索引
- Oracle訪問索引的執行計劃(三)Oracle索引
- Oracle訪問索引的執行計劃(四)Oracle索引
- Oracle訪問索引的執行計劃(五)Oracle索引
- JVM中物件訪問定位兩種方式JVM物件
- bash shell指令碼訪問PostgreSQL的三種方式指令碼SQL
- C#中陣列的三種訪問方式C#陣列
- 前端基礎問題:CSS居中的幾種方式前端CSS
- css引入的幾種方式CSS
- COOKIE的幾種操作方式Cookie
- 解析xml的幾種方式XML
- Unity反射的幾種方式Unity反射
- SpringMVC訪問靜態資源的三種方式SpringMVC
- 兩種訪問介面的方式(get和post)
- oracle產生事務transaction幾種方式或方法Oracle
- 【Oracle】 索引的掃描方式Oracle索引
- Linux禁止某個IP地址訪問的幾種方法Linux
- 程式碼迭代的幾種方式
- react 路由的幾種使用方式React路由
- JavaScript的幾種繼承方式JavaScript繼承
- OAuth的幾種授權方式OAuth
- js建立物件的幾種方式JS物件