索引的八種使用模式
索引,使用索引可快速訪問資料庫表中的特定資訊。索引是對資料庫表中一列或多列的值進行排序的一種結構。
在關聯式資料庫中,索引是一種與表有關的資料庫結構,它可以使對應於表的語句執行得更快。索引的作用相當於圖書的目錄,可以根據目錄中的快速找到所需的內容。當表中有大量記錄時,若要對錶進行查詢,第一種搜尋資訊方式是全表搜尋,是將所有記錄一一取出,和查詢條件進行一一對比,然後返回滿足條件的記錄,這樣做會消耗大量時間,並造成大量磁碟I/O操作;第二種就是在表中建立索引,然後在索引中找到符合查詢條件的索引值,最後透過儲存在索引中的ROWID(相當於頁碼)快速找到表中對應的記錄。
索引是一個單獨的、物理的資料庫結構,它是某個表中一列或若干列值的集合和相應的指向表中物理標識這些值的資料頁的邏輯清單。
索引提供指向儲存在表的指定列中的資料值的指標,然後根據您指定的排序順序對這些指標排序。資料庫使用索引的方式與您使用書籍中的索引的方式很相似:它搜尋索引以找到特定值,然後順指標找到包含該值的行。
點評:索引是提高語句效能的關鍵,而且不用修改程式!
該實驗的目的是深刻體會索引對資料庫的巨大影響。
索引在資料庫中是很重要的。沒有索引的資料庫是不可想象的,我們普通的表是無序的,也叫做堆表(heap table),一句話概括索引,索引是有序的結構,透過索引可以快速定位我們要找的行,避免全表掃描。索引的訪問模式有八種。
1.INDEX UNIQUE SCAN 效率最高,主鍵或唯一索引,走樹結構。
2.INDEX FAST FULL SCAN 讀所有塊,可以並行訪問索引,但輸出不按順序。
3.INDEX FULL SCAN 有順序的輸出,不能並行讀索引,走連結串列結構。
4.INDEX RANGE SCAN 給定的區間查詢,最常見的訪問模式。
5.INDEX SKIP SCAN 聯合索引的第二列為條件,不同值越少的列,越要放在前面。
6. SCAN DESCENDING 降序掃描,自動選擇降序使用索引。
7. index join 索引的連線,透過索引獲得全部資料,可以不掃描表。
8. bitmap join 索引的點陣圖連線,多個條件上的列都有索引的情況。
SQL> conn scott/tiger
Connected.
SQL> drop table t1 purge;
Table dropped.
SQL> create table t1 as select * from dba_objects;
Table created.
SQL> analyze table t1 compute statistics;
收集表t1的統計資訊
Table analyzed.
SQL> create unique index i2t1 on t1(object_id);
Index created.
SQL>set autot traceonly explain
1.INDEX UNIQUE SCAN 效率最高,主鍵或唯一索引
SQL> select * from t1 where object_id=9999;
Execution Plan
----------------------------------------------------------
Plan hash value: 1026981322
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 87 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 87 | 2 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | I2T1 | 1 | | 1 (0)| 00:00:01 |
執行計劃為唯一定位,最快。
2.INDEX FAST FULL SCAN 讀的最塊,可以並行訪問索引,但輸出不按順序
SQL> select object_id from t1 ;
Execution Plan
----------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 49859 | 194K| 337 (1)| 00:00:07 |
| 1 | TABLE ACCESS FULL| T1 | 49859 | 194K| 337 (1)| 00:00:07 |
為什麼沒有使用索引,而進行了全表掃描。因為object_id可能有null值。因為null不入普通索引。我們進行全索引的掃描就會得到錯誤的結果。這是全表掃描是正確的。雖然我們的的查詢僅包含了索引中的值。
我們如果有非空約束就會極大的提高效能。
SQL> delete t1 where object_id is null;
SQL> alter table t1 modify (OBJECT_ID not null);
SQL> select object_id from t1 ;
Execution Plan
----------------------------------------------------------
Plan hash value: 2003301201
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 49859 | 194K| 51 (2)| 00:00:02 |
| 1 | INDEX FAST FULL SCAN| I2T1 | 49859 | 194K| 51 (2)| 00:00:02 |
計劃僅掃描了索引,代價為51.因為所有的行都在索引中了,使用索引不會造成錯誤的結果。因為我們的輸出沒有要求有序,所以資料庫將高水位下所有的索引塊都讀一遍就可以了,這就叫索引的快速全掃描。
3.INDEX FULL SCAN 有順序的輸出,不能並行讀索引
SQL> select object_id from t1 order by object_id ;
Execution Plan
----------------------------------------------------------
Plan hash value: 1111347323
-------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 49859 | 194K| 106 (2)| 00:00:03 |
| 1 | INDEX FULL SCAN | I2T1 | 49859 | 194K| 106 (2)| 00:00:03 |
-------------------------------------------------------------------------
執行計劃為全掃描索引,含義是按葉子的大小順序來讀索引,因為我們要求輸出是有序的。
代價為106,高於快速全掃描,因為我們不是將高水位的塊連續讀,而是按照葉子的順序讀。正因為是按照葉子的順序讀,所以不能並行操作。
4.INDEX RANGE SCAN 給定的區間查詢
SQL> select * from t1 where object_id between 300 and 400;
Execution Plan
----------------------------------------------------------
Plan hash value: 1490405106
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 93 | 8091 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 | 93 | 8091 | 4 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | I2T1 | 93 | | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------
當我們的索引為非唯一,或者我們的索引唯一但查詢的條件為一個範圍的時候資料庫會選擇範圍定位。
代價的大小取決於你所查詢行的多少。
5.INDEX SKIP SCAN 聯合索引,不同值越少的列,越要放在前面
在下一個實驗聯合索引中有詳細的描述。
資料庫的主鍵,唯一約束和外來鍵的使用也要索引的參與。
SQL> drop table t2 purge;
Table dropped.
SQL> create table t2 as select distinct owner from dba_objects;
建立一個含有owner的表。
Table created.
SQL> alter table t2 add constraint pk_t2 primary key (owner);
建立主鍵
Table altered.
SQL> alter table t1 add constraint fk_t1 foreign key (owner)
references t2(owner) on delete cascade;;
建立一個級聯刪除的外來鍵
Table altered.
SQL>DELETE T2 WHERE OWNER='SYS';
檢視計劃,我們發現
Rows Row Source Operation
------- ---------------------------------------------------
1 DELETE T2 (cr=726 pr=0 pw=0 time=16740731 us)
1 INDEX UNIQUE SCAN PK_T2 (cr=1 pr=0 pw=0 time=52 us)(object id 54503)
Rows Row Source Operation
------- ---------------------------------------------------
0 DELETE T1 (cr=725 pr=0 pw=0 time=16714571 us)
22984 TABLE ACCESS FULL T1 (cr=690 pr=0 pw=0 time=160995 us)
在刪除t2的同時,要全表掃描t1表,因為我們建立了外來鍵。如果在外來鍵上有索引,那麼就很可能走索引,會極大的提高資料庫的效能。
6. SCAN DESCENDING 降序使用索引
SQL> SELECT * FROM EMP ORDER BY 1 DESC;
執行計劃
----------------------------------------------------------
Plan hash value: 3088625055
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 546 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 14 | 546 | 2 (0)| 00:00:01 |
| 2 | INDEX FULL SCAN DESCENDING| PK_EMP | 14 | | 1 (0)| 00:00:01 |
7. index join
SQL> spool c:\1.txt
SQL> conn scott/tiger
已連線。
SQL> drop table t1 purge;
表已刪除。
SQL> create table t1 as select * from dba_objects;
表已建立。
SQL> create index i1 on t1(object_name);
索引已建立。
SQL> create index i2 on t1(object_type);
索引已建立。
SQL> exec dbms_stats.gather_table_stats('SCOTT','T1');
PL/SQL 過程已成功完成。
SQL> set autot trace expl
SQL> SELECT OBJECT_NAME,OBJECT_TYPE FROM T1
2 WHERE OBJECT_NAME LIKE 'E%' AND OBJECT_TYPE='TABLE';
執行計劃
----------------------------------------------------------
Plan hash value: 1423132391
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 21 | 714 | 11 (10)| 00:00:01 |
|* 1 | VIEW | index$_join$_001 | 21 | 714 | 11 (10)| 00:00:01 |
|* 2 | HASH JOIN | | | | | |
|* 3 | INDEXRANGESCAN| I2 | 21 | 714 | 5 (0)| 00:00:01 |
|* 4 | INDEXRANGESCAN| I1 | 21 | 714 | 6 (17)| 00:00:01 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_TYPE"='TABLE' AND "OBJECT_NAME" LIKE 'E%')
2 - access(ROWID=ROWID)
3 - access("OBJECT_TYPE"='TABLE')
4 - access("OBJECT_NAME" LIKE 'E%')
8. bitmap join
SQL> SELECT COUNT(*) FROM T1 WHERE OBJECT_NAME LIKE 'E%' OR OBJECT_TYPE='TABLE';
執行計劃
----------------------------------------------------------
Plan hash value: 1019523335
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 34 | 11 (10)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 34 | | |
| 2 | BITMAP CONVERSION COUNT | | 2172 | 73848 | 11 (10)| 00:00:01 |
| 3 | BITMAP OR | | | | | |
| 4 | BITMAP CONVERSION FROM ROWIDS| | | | | |
|* 5 | INDEX RANGE SCAN | I2 | | | 5 (0)| 00:00:01 |
| 6 | BITMAP CONVERSION FROM ROWIDS| | | | | |
| 7 | SORT ORDER BY | | | | | |
|* 8 | INDEX RANGE SCAN | I1 | | | 5 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("OBJECT_TYPE"='TABLE')
8 - access("OBJECT_NAME" LIKE 'E%')
filter("OBJECT_NAME" LIKE 'E%' AND "OBJECT_NAME" LIKE 'E%')
索引使用總論:
能用唯一索引,一定用唯一索引
能加非空,就加非空約束
一定要統計表的資訊,索引的資訊,柱狀圖的資訊。
聯合索引的順序不同,影響索引的選擇,儘量將不同值少的列放在前面
如果你需要的列都存在於索引中,那麼資料庫只需要查詢索引而不去查詢表,大大提高系統的效能。
只有做到以上四點,資料庫才會正確的選擇執行計劃。
索引是在不修改程式碼的情況下提高效能的重要手段。索引也是約束的維護紐帶。在外來鍵上最好建立索引。
引數optimizer_index_cost_adj定義了索引的權重,該值越大,資料庫認為使用索引的成本越高,預設值為100,如果設定為50,那麼資料庫認為使用索引的代價比它計算出來的少一半,如果你設定為1000,那麼認為你使用索引的成本為計算出來的10倍,該值最大為10000,最小為1.
SQL> conn scott/tiger
Connected.
SQL> set autot on
SQL> alter session set optimizer_index_cost_adj = 100;
SQL> select * from emp order by empno;
這句話可以走索引,也可以不走索引。預設為100的情況。
Execution Plan
----------------------------------------------------------
Plan hash value: 4170700152
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 532 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 14 | 532 | 2 (0)| 00:00:01 |
| 2 | INDEX FULL SCAN | PK_EMP | 14 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
走了索引
SQL> select * from emp where empno between 1 and 1000;
no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 169057108
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 38 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 38 | 4 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | PK_EMP | 1 | | 2 (0)| 00:00:01 |
我們做了一個區間的範圍查詢,走了索引,進行了索引的範圍查詢。
SQL> alter session set optimizer_index_cost_adj=1000;
Session altered.
將該引數的值改為1000,資料庫評估索引的時候認為成本很高。
SQL> select * from emp order by empno;
Execution Plan
----------------------------------------------------------
Plan hash value: 150391907
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 532 | 5 (20)| 00:00:01 |
| 1 | SORT ORDER BY | | 14 | 532 | 5 (20)| 00:00:01 |
| 2 | TABLE ACCESS FULL| EMP | 14 | 532 | 4 (0)| 00:00:01 |
---------------------------------------------------------------------------
所以改為全表掃描了。
SQL> select * from emp where empno between 1 and 1000;
no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 3956160932
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 38 | 4 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| EMP | 1 | 38 | 4 (0)| 00:00:01 |
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29209863/viewspace-2128687/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 關於索引的使用模式索引模式
- 23種設計模式(八)-原型設計模式設計模式原型
- java23種設計模式——八、組合模式Java設計模式
- JAVA中實現單例(Singleton)模式的八種方式Java單例模式
- 經驗之談:八種Docker容器開發模式Docker模式
- [zt] Oracle不使用索引的幾種情況Oracle索引
- Windows XP 系統八種啟動模式詳解(轉)Windows模式
- OLSNODES命令的八種格式
- 設計模式(八)——策略模式設計模式
- NFT鏈遊開發:元宇宙中的八種新商業模式元宇宙模式
- oracle 索引和不走索引的幾種形式Oracle索引
- 索引的使用索引
- 設計模式(八)——橋接模式設計模式橋接
- 設計模式(八):裝飾模式設計模式
- oracle 為什麼沒有使用索引的一種情況Oracle索引
- 【索引】oracle查詢使用索引和不使用索引的比較索引Oracle
- mysql四種索引MySql索引
- 【索引】使用索引分析快速得到索引的基本資訊索引
- InnoDB學習(八)之 聚簇索引索引
- 八、目前JDK中,單例模式這3種寫法你知道嗎?JDK單例模式
- 字首索引,一種優化索引大小的解決方案索引優化
- CSS 隱藏元素的八種方法CSS
- 設計模式(八)裝飾器模式設計模式
- 使用何種模式,問題新描述?模式
- 設計模式(八)Context中的裝飾者模式設計模式Context
- oracle 索引訪問的幾種方式Oracle索引
- Gin(八):cookie的使用Cookie
- 設計模式快速學習(八)委派模式設計模式
- 設計模式第八講-狀態模式設計模式
- Oracle索引梳理系列(六)- Oracle索引種類之函式索引Oracle索引函式
- 八種改變未來的技術
- ios 遍歷陣列的八種方法iOS陣列
- 程式設計師的八種級別程式設計師
- 人際關係的八種距離
- Excel小技巧-公式和函式使用的常見八種錯誤合集Excel公式函式
- ESB的幾種模式模式
- kubeproxy 的三種模式模式
- Flutter Provider狀態管理---八種提供者使用分析FlutterIDE