索引建立原則
- 確定針對該表的操作是大量的查詢操作還是大量的增刪改操作。
- 嘗試建立索引來幫助特定的查詢。檢查自己的sql語句,為那些頻繁在where子句中出現的字段建立索引。
- where語句中不得不對查詢列采用函數查詢,如upper函數,最好建立相應函數索引;
- 在SQL語句中經常進行GROUP BY、ORDER BY的字段上建立索引
- 用於聯接的列(主健/外健)上建立索引;
- 在經常存取的多個列上建立復合索引,但要注意復合索引的建立順序要按照使用的頻度來確定;
- 嘗試建立復合索引來進一步提高系統性能。修改復合索引將消耗更長時間,同時,復合索引也占磁盤空間。
- 對於小型的表,建立索引可能會影響性能
- 在不同值較少的字段上不必要建立索引,如性別字段;
- 應該避免對具有較少值的字段進行索引。???
- 避免選擇大型數據類型的列作為索引。
- 缺省情況下建立的是非簇集索引,但在以下情況下最好考慮簇集索引,如:含有有限數目(不是很少)唯一的列;進行大范圍的查詢;
- 充分的利用索引可以減少表掃描I/0的次數,有效的避免對整表的搜索。當然合理的索引要建立在對各種查詢的分析和預測中
- 避免在有大量並發DML運算的表中使用Bitmap索引;
- 經常被更新,或者一個表雖然很大,但是如果多數查詢返回結果都超過表中總行數的4%,那么一般認為也是不宜建立索引的。
- 經常查詢的記錄數目少於表中所有記錄總數的5%時就應當創建索引
- 存儲索引的表空間最好單獨設定
- 隨着數據的變化,索引的效率會下降,因此應定期重建索引
oracle位圖索引 B-樹索引
B-樹索引在Oracle中是一個通用的索引,在創建索引時它就是默認的索引類型。最多可以包括32列。
創建語句:create index indexName on tableName(columnName);
特點:
1.索引不存儲null值。更准確的說,單列索引不存儲null值,復合索引不存儲全為Null的值。索引不能存儲Null,所以對這列采用is null條件時,因為索引上根本沒Null值,不能利用到索引,只能全表掃描。
2.不適合鍵值較少的列。與數據塊有關。
3.前導模糊查詢不能利用索引(like '%XX'或者like '%XX%')。這樣會導致全表掃描。
位圖索引Oracle為每個唯一鍵創建一個位圖,然后把與鍵值所關聯的ROWID保存為位圖。最多可以包括30列。
創建語句:create bitmap index indexName on tableName(columnName);
特點:
1.相對於B*Tree索引,占用的空間非常小,創建和使用非常快。位圖索引由於只存儲鍵值的起止Rowid和位圖,占用的空間非常少。
2.不適合鍵值較多的列。
3.不適合update、insert、delete頻繁的列。
4.可以存儲null值。B*Tree索引由於不記錄空值,當基於is null的查詢時,會使用全表掃描,而對位圖索引列進行is null查詢時,則可以使用索引。
5.當select count(XX) 時,可以直接訪問索引中一個位圖就快速得出統計數據。
6.當根據鍵值做and,or或 in(x,y,..)查詢時,直接用索引的位圖進行或運算,快速得出結果行數據。
位圖索引有很多限制:
基於規則的優化器不會考慮位圖索引
當執行ATLER TABLE語句,並修改包含有位圖索引的列時,會使位圖索引失效
位圖索引在索引塊中儲存了索引鍵的值;然而,他們並不能用戶任何類型的完整性檢查
位圖索引不能被申明為唯一索引
索引不會被命中的情況
1、查詢謂詞沒有使用索引的主要邊界,可能會導致不走索引。
查詢:SELECT * FROM T WHERE Y=XXX;
假如T表上有一個包含Y值的組合索引,但是優化器會認為需要一行行的掃描會更有效,這個時候,優化器可能會選擇TABLE ACCESS FULL,
查詢換成:SELECT Y FROM T WHERE Y = XXX,優化器會直接去索引中找到Y的值,因為從B樹中就可以找相應的值。
2、如果在B樹索引中有一個空值的時候,優化器可能不會走索引。
查詢:那么查詢諸如SELECT COUNT(*) FROM T
有兩種方式可以讓索引有效,一種是SELECT COUNT(*) FROM T WHERE XXX IS NOT NULL或者是不能為空。
3、在索引字段上使用函數,導致不會走索引。
查詢:SELECT * FROM T WHERE FUN(Y) = XXX。
如果在T表上有一個索引Y時,索引也不會被用到,因為你要查詢的列中所有的行都需要被計算一遍,
可以在這個表上建立一個基於函數的索引,比如CREATE INDEX IDXFUNT ON T(FUN(Y));這種方式,等於Oracle會建立一個存儲所有函數計算結果的值,再進行查詢的時候就不需要進行計算了。
4、索引不適用於隱式轉換的情況。
查詢:SELECT * FROM T WHERE Y = 5
在Y上面有一個索引,但是Y列是VARCHAR2的,那么Oracle會將上面的5進行一個隱式的轉換成SELECT * FROM T WHERE TO_NUMBER(Y) = 5,這個時候也是有可能用不到索引的。
5、如果表只有幾個數據塊大小,而且可以被Oracle一次性抓取,那么就沒有使用索引的必要了,因為抓取索引還需要去根據rowid從數據塊中獲取相應的元素值,因此在表特別小的情況下,索引沒有用到是情理當中的事情。