一、概述
建立索引時,將在表空間自動地建立一個索引段,索引段空間分配和保留空間的使用受到下列控制:
索引段範圍的分配受常駐該索引段的存儲參數控制;其數據塊中未用空間可受該段的PCTFREE參數設置所控制。
二、創建索引的兩種方式
1.自動創建:在定義主鍵或唯一性約束時系統會自動在相應的字段上創建unique索引。
2.手動創建:用戶可以在其它列上創建非唯一索引,以加速查詢。如果創建unique索引則也會自動實施unique約束。
三、創建索引的原則
創建索引一般有以下兩個目的:維護被索引列的唯一性和提供快速訪問表中數據的策略。
1、在select操作佔大部分的表上創建索引;
2、在where子句中出現最頻繁的列上創建索引;
3、在選擇性高的列上創建B-TREE索引(補充索引選擇性,最高是1,eg:primary key);
4、複合索引的主列應該是最有選擇性的和where限定條件最常用的列,並以此類推第二列……。
5、小於5M的表,最好不要使用索引來查詢,表越小,越適合用全表掃描。
四、使用索引的原則
1、查詢結果是所有數據行的5%以下時,使用B-TREEindex查詢效果最好;
2、where條件中經常用到表的多列時,使用複合索引效果會好於幾個單列索引。因爲當sql語句所查詢的列,全部都出現在複合索引中時,
此時由於Oracle只需要查詢索引塊即可獲得所有數據,當然比使用多個單列索引要快得多;
3、索引利於select,但對經常insert,delte尤其update的表,會降低效率。
4、where子句中的這個字段,必須是複合索引的第一個字段;eg:一個索引是按f1, f2, f3的次序建立的,
若where子句是f2 = :var2,則因爲f2不是索引的第1個字段,無法使用該索引,9i後引用index skip scan解決了這個問題
5、where子句中的這個字段,不應該參與任何形式的計算:任何對列的操作都將導致表掃描,它包括數據庫函數、計算表達式等等,查詢時要儘可能將操作移至等號右邊。
6、應儘量熟悉各種操作符對Oracle是否使用索引的影響:以下這些操作會顯式(explicitly)地阻止 Oracle 使用索引:
is null;is not null;notin;!=;like;numeric_col+0;date_col+0;char_col||' ';to_char;to_numberto_date等。
五、索引特點
第一,通過創建唯一性索引,可以保證數據庫表中每一行數據的唯一性。
第二,可以大大加快數據的檢索速度,這也是創建索引的最主要的原因。
第三,可以加速表和表之間的連接,特別是在實現數據的參考完整性方面特別有意義。
第四,在使用分組和排序子句進行數據檢索時,同樣可以顯著減少查詢中分組和排序的時間。
第五,通過使用索引,可以在查詢的過程中,使用優化隱藏器,提高系統的性能。
六、應該建索引列的特點:
1)在經常需要搜索的列上,可以加快搜索的速度;
2)在作爲主鍵的列上,強制該列的唯一性和組織表中數據的排列結構;
3)在經常用在連接的列上,這些列主要是一些外鍵,可以加快連接的速度;
4)在經常需要根據範圍進行搜索的列上創建索引,因爲索引已經排序,其指定的範圍是連續的;
5)在經常需要排序的列上創建索引,因爲索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間;
6)在經常使用在WHERE子句中的列上面創建索引,加快條件的判斷速度。
七、不應該建索引列的特點:
第一,對於那些在查詢中很少使用或者參考的列不應該創建索引。這是因爲,既然這些列很少使用到,因此有索引或者無索引,並不能提高查詢速度。
相反,由於增加了索引,反而降低了系統的維護速度和增大了空間需求。
第二,對於那些只有很少數據值的列也不應該增加B-TREE索引。這是因爲,由於這些列的取值很少,
例如人事表的性別列,在查詢的結果中,結果集的數據行佔了表中數據行的很大比例,即需要在表中搜索的數據行的比例很大。增加B-TREE索引,並不能明顯加快檢索速度。
第三,對於那些定義爲 blob數據類型的列不應該增加索引。這是因爲,這些列的數據量要麼相當大,要麼取值很少。
第四,當修改性能遠遠大於檢索性能時,不應該創建索引。這是因爲,修改性能和檢索性能是互相矛盾的。
當增加索引時,會提高檢索性能,但是會降低修改性能。當減少索引時,會提高修改性能,降低檢索性能。因此,當修改性能遠遠大於檢索性能時,不應該創建索引。
八、索引不足
第一,創建索引和維護索引要耗費時間,這種時間隨着數據量的增加而增加。
第二,索引需要佔物理空間,除了數據表佔數據空間之外,每一個索引還要佔一定的物理空間,如果要建立聚簇索引,那麼需要的空間就會更大。
第三,當對錶中的數據進行增加、刪除和修改的時候,索引也要動態的維護,這樣就降低了數據的維護速度。
九、創建索引的語法
CREATEUNIUQE | BITMAP INDEX <schema>.<index_name>
ON <schema>.<table_name>
(<column_name> |<expression> ASC | DESC,
<column_name> |<expression> ASC | DESC,...)
TABLESPACE <tablespace_name>
STORAGE <storage_settings>
LOGGING | NOLOGGING
COMPUTE STATISTICS
NOCOMPRESS | COMPRESS<nn>
NOSORT | REVERSE
PARTITION | GLOBALPARTITION<partition_setting>
相關說明
1) UNIQUE | BITMAP:指定UNIQUE爲唯一值的B-Tree索引, BITMAP爲位圖索引,省略爲非唯一值的B-Tree索引。
2) <column_name> |<expression> ASC | DESC:可以對多列進行聯合索引,當爲expression時即“基於函數的索引”
3) TABLESPACE:指定存放索引的表空間 (索引和原表不在一個表空間時效率更高)
4) STORAGE:可進一步設置表空間的存儲參數
5) LOGGING | NOLOGGING:是否對索引產生重做日誌(對大表儘量使用 NOLOGGING來減少佔用空間並提高效率)
6) COMPUTE STATISTICS:創建新索引時收集統計信息
7) NOCOMPRESS | COMPRESS<nn>:是否使用“鍵壓縮”(使用鍵壓縮可以刪除一個鍵列中出現的重複值)
8) NOSORT | REVERSE:NOSORT表示與表中相同的順序創建索引, REVERSE表示相反順序存儲索引值
9) PARTITION | NOPARTITION:可以在分區表和未分區表上對創建的索引進行分區
另外
createindex index_name1 on student(sid,sname);
createindex index_name2 on student(sname,sid);
這兩種索引方式是不一樣的
索引index_name1對Select * from student where sid=1; 這樣的查詢語句有效
索引index_name2對Select * from student where sname=?; 這樣的查詢語句有效
因此建立複合索引的時候,字段的組合順序是非常重要的。一般情況下,需要經常訪問的字段放在組合字段的前面
Oracle9i引入跳躍式掃描,解決了上述問題,即使Oracle不走索引也可以加hint。
十、索引的存儲
索引和表都是獨立存在的。在爲索引指定表空間的時候,不要將被索引的表和索引指向同一個表空間,這樣可以避免產生IO衝突。
使Oracle能夠並行訪問存放在不同硬盤中的索引數據和表數據,更好的提高查詢速度。
十一、刪除索引
dropindex PK_DEPT1;
十二、索引的失效
1.6.1 使用不等於操作符(<>、 !=)
下面的查詢即使在cust_rating列有一個索引,查詢語句仍然執行一次全表掃描。
select cust_Id,cust_name from customerswhere cust_rating <> 'aa';
把上面的語句改成如下的查詢語句,這樣,在採用基於規則的優化器而不是基於代價的優化器(更智能)時,將會使用索引。
select cust_Id,cust_name from customers wherecust_rating < 'aa' or cust_rating > 'aa';
特別注意:通過把不等於操作符改成 OR條件,就可以使用索引,以避免全表掃描。
1.6. 2使用 IS NULL 或 IS NOT NULL
使用 IS NULL 或 IS NOT NULL同樣會限制索引的使用。因爲 NULL值並沒有被定義。在 SQL語句中使用 NULL會有很多的麻煩。因此建議開發人員在建表時,把需要索引的列設成 NOT NULL。如果被索引的列在某些行中存在 NULL值,就不會使用這個索引(除非索引是一個位圖索引,關於位圖索引在稍後在詳細討論)。
1.6 .3使用函數
如果不使用基於函數的索引,那麼在SQL語句的 WHERE子句中對存在索引的列使用函數時,會使優化器忽略掉這些索引。
下面的查詢不會使用索引(只要它不是基於函數的索引)
select empno,ename,deptno from emp where trunc(hiredate)='01-MAY-81';
把上面的語句改成下面的語句,這樣就可以通過索引進行查找。
selectempno,ename,deptno from emp where hiredate<(to_date('01-MAY-81')+0.9999);
1.6 .4比較不匹配的數據類型
也是比較難於發現的性能問題之一。注意下面查詢的例子,account_number是一個 VARCHAR2類型 ,在 account_number字段上有索引。
下面的語句將執行全表掃描:
select bank_name,address,city,state,zip frombanks where account_number = 990354;
Oracle可以自動把 where子句變成 to_number(account_number)=990354,這樣就限制了索引的使用 ,改成下面的查詢就可以使用索引:
select bank_name,address,city,state,zip frombanks where account_number ='990354';
特別注意:不匹配的數據類型之間比較會讓Oracle自動限制索引的使用 ,即便對這個查詢執行Explain Plan也不能讓您明白爲什麼做了一次“全表掃描”
十三、管理索引
1)先插入數據後創建索引
向表中插入大量數據之前最好不要先創建索引,因爲如果先建立索引。那麼在插入每行數據的時候都要更改索引。這樣會大大降低插入數據的速度。
2)設置合理的索引列順序
3)限制每個表索引的數量
4)刪除不必要的索引
5)爲每個索引指定表空間
6)經常做insert,delete尤其是update的表最好定期exp/imp表數據,整理數據,降低碎片(缺點:要停應用,以保持數據一致性,不實用);
有索引的最好定期rebuild索引(rebuild期間只允許表的select操作,可在數據庫較空閒時間提交),以降低索引碎片,提高效率
十四、注意的地方
1.建立索引將佔用額外的數據庫空間,更重要的是增刪改操作的時候,索引的排序也必須改變,加大的維護的成本。
2.如果經常查詢x=?和y=?,那推薦使用組合index(x,y),這種情況下組合索引的效率是遠高於兩個單獨的索引的。
3.同時在用組合索引的時候,大家一定要注意一個細節:建立組合索引index(x,y,z)的時候,那在查詢條件中出現x,xy,xyz,yzx都是可以用到該組合索引,但是y,yz,z是不能用到該索引的。
十五、索引的啓用與警用
啓動索引監視:alter index index_name monitoring usage;
停止索引監視:alter index index_name nomonitoringusage;
十六、索引的重建
Oracle index rebuild online與 rebuild及 drop index後重建?
當我們對索引進行 rebuild時,如果不加online選項,oracle則直接讀取原索引的數據;
當我們添加 online選項時,oracle是直接掃描表中的數據,維護索引段數據的一致性就是從索引開始創建到索引創建完成這段時間的數據改變的同步。
從索引開始 rebuild online的那一刻起,oracle會先創建一個SYS_JOURNAL_xxx的系統臨時日誌表,結構類似於物化視圖日誌表mlog$_表,
通過內部觸發器,記錄了開始 rebuildonline索引時表上所發生的改變的記錄,當索引已經創建好之後,
新數據將直接寫入索引,只需要把SYS_JOURNAL_xxx日誌表中的改變維護到索引中即可,也就是最小化對當前業務的影響。
在 rebulid index online的時候走的是 full table scan,這時候需要排序;
在 rebulid index走的index ffs,而ffs搜索的順序是根據leafblock的物理存儲順序相關,也需要排序。在rebuild index時候還是需要用到temp空間來排序的。
總之,優先用rebuild online,實在不行也要在空閒的時候用rebuil,非必要不用drop index/create index
ALTERINDEX index_name REBUILD;
ALTERINDEX index_name REBUILD ONLINE;
alter index index_name rebuild tablespace tablespace_name --重建時重設存儲的表空間
全局非分區索引
CREATEINDEX month_ix ON sales (sales_month);
等同於
CREATEINDEX month_ix ON sales (sales_month) GLOBAL;
局部索引的基表必須是分區表
在Oracle中可以創建組合索引,即同時包含兩個或兩個以上列的索引。在組合索引的使用方面,Oracle有以下特點:
1、當使用基於規則的優化器(RBO)時,只有當組合索引的前導列出現在SQL語句的where子句中時,纔會使用到該索引;
2、在使用Oracle9i之前的基於成本的優化器(CBO)時,只有當組合索引的前導列出現在SQL語句的where子句中時,纔可能會使用到該索引,這取決於優化器計算的使用索引的成本和使用全表掃描的成本,Oracle會自動選擇成本低的訪問路徑;
3、從Oracle9i起,Oracle引入了一種新的索引掃描方式——索引跳躍掃描(index skip scan),這種掃描方式只有基於成本的優化器(CBO)才能使用。這樣,當SQL語句的where子句中即使沒有組合索引的前導列,並且索引跳躍掃描的成本低於其他掃描方式的成本時,Oracle就會使用該方式掃描組合索引;
4、 Oracle優化器有時會做出錯誤的選擇,因爲它再“聰明”,也不如我們SQL語句編寫人員更清楚表中數據的分佈,在這種情況下,通過使用提示(hint),我們可以幫助Oracle優化器作出更好的選擇。
十七、索引類型
1、B樹索引(B-Tree Index)
創建索引的默認類型,結構是一顆二叉樹,採用的是平衡B樹算法:右子樹節點的鍵值大於等於父節點的鍵值,左子樹節點的鍵值小於等於父節點的鍵值。
B樹索引可是單列索引,也可是複合(也稱組合)索引索引,最多可以包括32列。
樹葉塊包含了索引值、ROWID,以及指向前一個和後一個樹葉塊的指針。Oracle可以從兩個方向遍歷這個二叉樹。B樹索引保存了在索引列上有值的每個數據行的ROWID值。
Oracle不會對索引列上包含NULL值的行進行索引。如果索引是多個列的組合索引,而其中列上包含NULL值,這一行就會處於包含NULL值的索引列中,且將被處理爲空(視爲NULL)。
技巧:索引列的值都存儲在索引中。因此,可以建立一個組合(複合)索引,這些索引可以直接滿足查詢,而不用訪問表。這就不用從表中檢索數據,從而減少了I/O量
B-tree 特點:
適合與大量的增、刪、改(OLTP)
不能用包含OR操作符的查詢;(and可以)
適合高基數的列(唯一值多)
典型的樹狀結構;
每個結點都是數據塊;
大多都是物理上一層、兩層或三層不定,邏輯上三層;
葉子塊數據是排序的,從左向右遞增;
在分支塊和根塊中放的是索引的範圍;
例子表temp_liutao字段A有索引,B/C沒有索引,則下列OR語句無法使用A的索引,除非A\B列均有索引。
select/*+index(t ind_temp_liutao_a)*/ *
from temp_liutao t
where t.a = 'a1' or t.b = 'b1' and t.c='c1';
2、位圖索引(BitMap Index)
如果表中的某些字段取值範圍比較小,比如職員性別、分數列ABC級等。只有兩個值。這樣的字段如果建B樹索引沒有意義,不能提高檢索速度。這時我們推薦用位圖索引
位圖索引非常適合於決策支持系統(Decision Support System,DSS)和數據倉庫,它們不應該用於通過事務處理應用程序訪問的表。
它們可以使用較少到中等基數(不同值的數量)的列訪問非常大的表。儘管位圖索引最多可達30個列,但通常它們都只用於少量的列。
因位圖索引合併機制的存在,且index skip scan不能用於位圖索引的組合形式,故可以說位圖索引並適合用組合索引。
例如,您的表可能包含一個稱爲Sex的列,它有兩個可能值:男和女。這個基數只爲 2。
如果有多個可用的位圖索引, Oracle就可以合併從每個位圖索引得到的結果集,快速刪除不必要的數據。
創建3個單列位圖索引
下面體現合併的處理
Bitmap t特點:
適合與決策支持系統;
做UPDATE代價非常高;
非常適合OR操作符的查詢;
基數比較少的時候才能建位圖索引;
技巧:當大多數條目不會向位圖添加新的值時,位圖索引在批處理(單用戶 )操作中加載表 (插入操作 )方面通常要比 B樹做得好。
當多個會話同時向表中插入行時不應該使用位圖索引,在大多數事務處理應用程序中都會發生這種情況。
技巧:位圖索引使用固定長度的數據類型要比可變長度的數據類型好。較大尺寸的塊也會提高對位圖索引的存儲和讀取性能。
技巧:建議不要在一些聯機事務處理(OLTP)應用程序中使用位圖索引。B樹索引的索引值中包含 ROWID,這樣 Oracle就可以在行級別上鎖定索引。
位圖索引存儲爲壓縮的索引值,其中包含了一定範圍的 ROWID,因此 Oracle必須針對一個給定值鎖定所有範圍內的 ROWID。這種鎖定類型可能在某些DML語句中造成死鎖。 SELECT語句不會受到這種鎖定問題的影響。
位圖索引的使用 限制 :
基於規則的優化器不會考慮位圖索引。
當執行ALTER TABLE語句並修改包含有位圖索引的列時,會使位圖索引失效。
位圖索引不包含任何列數據,並且不能用於任何類型的完整性檢查。
位圖索引不能被聲明爲唯一索引。
位圖索引的最大長度爲30。
3、基於函數的索引
如果沒有基於函數的索引,任何在列上執行了函數的查詢都不能使用這個列的索引。
建立它們之前必須先考慮下面一些問題:
能限制在這個列上使用的函數嗎?如果能,能限制所有在這個列上執行的所有函數嗎
是否有足夠應付額外索引的存儲空間?
在每列上增加的索引數量會對針對該表執行的DML語句的性能帶來何種影響?
基於函數的索引非常有用,但在實現時必須小心。在表上創建的索引越多,INSERT、 UPDATE和 DELETE語句的執行就會花費越多的時間。
注意:對於優化器所使用的基於函數的索引來說,必須把初始參數QUERY_REWRITE_ENABLED設定爲 TRUE。
4、HASH索引
http://justplayoop1.iteye.com/blog/1259562
5、索引組織表
http://justplayoop1.iteye.com/blog/1259562
6、反轉鍵索引
http://justplayoop1.iteye.com/blog/1259562
7、位圖連接索引
http://justplayoop1.iteye.com/blog/1259562
參考文獻:
http://justplayoop1.iteye.com/blog/1259562