Oracle索引簡介
一、rowid
1.解釋
rowid的值在一行資料插入到資料庫的表中時即被確定且唯一,通過它可以訪問資料庫表中的單行資料。rowid是一個偽列,它實際並不存在於表中,它是Oracle在讀取表中資料是,根據沒一行資料的實體地址資訊編碼而成的一個偽列。使用rowid來做單位記錄定位速度最快。
2.rowid的構成
共18位,基於base64編碼,分為四個部分
- OOOOOOFFFBBBBBBRRR
- OOOOOO——6位,物件編號,該行資料所在的資料物件的 data_object_id;
- FFF——3位,檔案編號,該行資料所在的相對資料檔案的id,用於確定datafile的編號;
- BBBBBB——6位,塊編號,是相對於datafile的編號,是該行所在資料塊的編號;
- RRR——3位,行編號;
3.如何從rowid計算得到obj#,rfile#,block#,row#
- rowid用A~Z a~z 0~9 + /共64個字元表示。
- A表示0,B表示1,……
- a表示26,b表示27,……
- 0表示52,……
- +表示62,/表示63 可以將其視為64進位制的數。
- obj#=AAAGbE=6*64^2+27*64+4=26308 rfile#=AAH=7 block#=AAAABB8=64+60=124
4.rowid的內部儲存格式
雖然我們從rowid偽列中select出來的rowid是以base64字元顯示的,但是再oracle內部儲存的時候還是以原值的二進位制形式儲存的。
一個擴充套件rowid用10byte來儲存,共8*10bit,obj#32b,rfile#10b,block#22b,row#16b。所以一個數據庫內不能有超過2^32=4G個Object,相對檔案號不能超過2^10-1個(不存在檔案號為0的檔案), 一個datafile只能有2^22=4M個塊,一個塊中不能超過2^16行資料。
5.Index中儲存的rowid
索引就是保留了rowid後三個部分,可以快速地定位到資料行。
二、索引的概念及語法
1. 索引概述
索引與表一樣,屬於段(segment)的一種,裡面存放了使用者的資料,跟表一樣需要佔用磁碟空間。
在關係資料庫中,索引是一種單獨的、物理的對資料庫表中一列或多列的值進行排序的一種儲存結構,它是某個表中一列或若干列值的集合和相應的指向表中物理標識這些值的資料頁的邏輯指標清單。 ——“百度百科”
它獨立於表的物件,可以存放於不同的表空間中,索引直接指向行資料的物理儲存,減少磁碟 i/o ,Oracle自動使用並維護索引,插入、刪除、更新表後,自動跟新索引。
2.索引的用法
- 建立索引
create index <index_name> on <table_name> (<col_name>)[tablespace<tablespace_name>];
- 重置索引
alter index <index_name> rebuild;
--REBUILD 是根據原來的索引結構重新建立索引,實際是刪除原來的索引後再重新建立。
- 刪除索引
drop index <index_name>;
三、索引的分類
1.B樹索引(預設)
B樹索引可以是單列索引也可以是組合索引,B樹索引最多可以包括32列。索引列的值都儲存在索引表中,對應了一個物理位置,從而不用訪問表就可以查詢到行。
特點:
- 適合大量增、刪、改
- 適合高基數的列,即列的值重複率低
- 不能用包含or操作的查詢
- 是樹狀結構,每個節點都是資料塊
- 葉子塊資料從左往右遞增
- 在分支塊和根塊中放的是索引的範圍
create index <index_name> on <table_name>(<col_name>);
2.點陣圖索引
點陣圖索引非常適合於DSS和資料倉庫,但不適用於OLTP訪問的表。點陣圖索引使用點陣圖作為鍵值,對於表中的每一資料行,點陣圖包含了TRUE/FALSE,0/1,NULL值。
特點:
- 適合較低基數的列,如:性別
- 適合含OR操作符的查詢
- update的代價高,因為要更新所有的bitmap
- 點陣圖以一種壓縮格式村反覆,因此佔用的磁碟空間比標準索引要小得多
create bitmap index <index_name> on <table_name>(<col_name>)
3.唯一索引
當某列任意兩行值都不等時,當建立主鍵或者唯一約束時唯一索引將會被建立。
create unique index <index_name> on <table_name>(<col_name>);
4.基於函式的索引
可以在表中建立基於函式的索引,如果沒有基於函式的索引,任何地方在列上執行了函式的查詢都不能使用這個列的索引。因為索引儲存的值只有是查詢的值時才有用,索引只是鍵值對的形式儲存,並不會去做函式運算。
例如:
--它不會使用job列上的索引
select * from emp where UPPER(job)='MGR';
--它會使用job列上的索引,但是查詢的條件又不符合要求
select * from emp where job='MRG'
--此時可以用函式索引,這是對錶達式UPPER(job)建立的索引,儲存的值是UPPER(job)的結果
create index EMP$UPPER_JOB on emp(UPPER(job));
函式包括:算術表示式、PL/SQL函式、程式包函式、SQL函式、自定義函式
CREATE INDEX <index_name> ON <table_name>(<function_name>(<column_name>))
注意: &emps&emps基於函式的索引非常有用,但在實現時必須小心。在表上建立的索引越多,INSERT、UPDATE 和 DELETE
語句的執行就會花費越多的時間。 注意:對於優化器所使用的基於函式的索引來說,必須把初始引數 QUERY_REWRITE _ ENABLED
設定為 TRUE。
5.組合索引
當兩個或者多個列經常一起出現在where條件中時,在這些列上同時建立組合索引。
特點:
- 組合索引的列的順序是任意的
- 如果where子句中引用了組合索引的大多數列,則可以提高效率
- 建議將訪問最頻繁的列放在組合索引列的最前面
CREATE INDEX <index_name> ON <table_name>(<col_name1>,<col_name2>);
6.索引組織表(IOT)
索引組織表會把表的儲存結構改成 B 樹結構,以表的主鍵進行排序,ROWID 並沒有被關聯到表的行上。這種特殊的表和其他型別的表一樣,可以在表上執行所有的 DML 和 DDL 語句。
對於一些涉及精確匹配和範圍搜尋的語句,索引組織表提供了一種基於鍵的快速資料訪問機制。
基於主鍵值的 UPDATE 和 DELETE 語句的效能也同樣得以提高,這是因為行在物理上有序。由於鍵列的值在表和索引中都沒有重複,儲存所需要的空間也隨之減少。
如果不會頻繁地根據主鍵列查詢資料,則需要在索引組織表中的其他列上建立二級索引。
必須指定主鍵。插入資料時,會根據主鍵列進行B樹索引排序,寫入磁碟。
對於總是通過對主鍵的精確匹配或範圍掃描進行訪問的表,就需要考慮使用索引組織表,可以在索引組織表上建立二級索引 。
7.反向鍵索引
當載入一些有序資料時,建立普通索引肯定會碰到與 I/O 相關的一些瓶頸。為了解決這個問題, 可以把索引表空間存放在能夠把檔案物理分割在多個磁碟上的磁碟體系結構上。詳見:ORACLE索引的作用及用法
缺點:
- 由於反向索引結構自身的特點,如果系統中經常使用範圍掃描進行讀取資料的話(例如在where子句中使用“between and”語句或比較運算子“>”“<”等),那麼反向索引將不適用,因為此時會出現大量的全表掃描的現象,反而會降低系統的效能。
- 有時候可以通過改寫sql語句來避免使用範圍掃描,例如where id between 12345 and 12347,可以改寫為where id in(12345,12346,12347),CBO會把這樣的sql查詢轉換為where id=12345 or id=12346 or id=12347,這對反向索引也是有效的。
- 不可以將反轉鍵索引與點陣圖索引或索引組織表結合使用。因為不能對點陣圖索引和索引組織表進行反轉鍵處理。
create index <index_name> on <table_name>(column_name) reverse;
8.HASH 索引
使用 HASH 索引必須要使用 HASH 叢集。建立一個叢集或 HASH 叢集的同 時,也就定義了一個叢集鍵。這個鍵告訴 Oracle 如何在叢集上儲存表。在儲存資料時,所有與這個叢集鍵相關的行都被儲存在一個數據庫塊上。HASH 索引在有限制條件(需要指定一個確定的值而不是一個值範圍)的情況下非常有用。
特點:
- 如果不能為叢集的未來增長分配好附加的空間,HASH 叢集可能就不 是最好的選擇;
- 如果應用程式經常在叢集表上進行全表掃描,HASH叢集可能也不是最好的選擇;
- 通常,HASH 對於一些包含有序值的靜態資料非常有效;
四、總結
比較適合建立索引的列的特點:
- 經常需要搜尋的列上
- 主鍵,一般建立唯一性索引,保持資料的唯一性
- 外來鍵,提高表與表之間連線的速度 需要排序的列上
- where子句後邊經常出現的欄位
- 經常需要根據範圍進行搜尋的列上,比如日期
不適合建立索引的列的特點:
- 很少進行搜尋的列
- 列取值比較少的列上
- blob型別的列上 修改頻率比較高的列上
使用索引的限制:
- 不能使用不等於<> 、 != ,(不等於操作符一定會進行全表掃描)
- 使用is null 、 is not null(只要索引中出現一個null,那麼這個索引就報廢了。所以在建立索引的時候,一定要將準備建立索引的列設定為not null)
- 使用函式(where子句中含有trunc()、add_months()之類)的時候,sql優化器會自動忽略掉索引
- where子句中,進行了資料型別不匹配的比較,比如(where row_num = ‘1’)的時候,會限制索引的使用
索引查詢:
- dba_indexes
- user_indexes
- uesr_ind_columns