基於合理的數據庫設計,經過深思熟慮后為表建立索引,是獲得高性能數據庫系統的基礎。而未經合理分析便添加索引,則會降低系統的總體性能。索引雖然說提高了數據的訪問速度,但同時也增加了插入、更新和刪除操作的處理時間。
是否要為表增加索引、索引建立在哪些字段上,是創建索引前必須要考慮的問題。解決此問題的一個比較好的方法,就是分析應用程序的業務處理、數據使用,為經常被用作查詢條件、或者被要求排序的字段建立索引。基於優化器對SQL語句的優化處理,我們在創建索引時可以遵循下面的一般性原則:
(1)為經常出現在關鍵字order by、group by、distinct后面的字段,建立索引。
在這些字段上建立索引,可以有效地避免排序操作。如果建立的是復合索引,索引的字段順序要和這些關鍵字后面的字段順序一致,否則索引不會被使用。
(2)在union等集合操作的結果集字段上,建立索引。其建立索引的目的同上。
(3)為經常用作查詢選擇的字段,建立索引。
(4)在經常用作表連接的屬性上,建立索引。
(5)考慮使用索引覆蓋。對數據很少被更新的表,如果用戶經常只查詢其中的幾個字段,可以考慮在這幾個字段上建立索引,從而將表的掃描改變為索引的掃描。
除了以上原則,在創建索引時,我們還應當注意以下的限制:
(1)限制表上的索引數目。
對一個存在大量更新操作的表,所建索引的數目一般不要超過3個,最多不要超過5個。索引雖說提高了訪問速度,但太多索引會影響數據的更新操作。
(2)不要在有大量相同取值的字段上,建立索引。
在這樣的字段(例如:性別)上建立索引,字段作為選擇條件時將返回大量滿足條件的記錄,優化器不會使用該索引作為訪問路徑。
(3)避免在取值朝一個方向增長的字段(例如:日期類型的字段)上,建立索引;對復合索引,避免將這種類型的字段放置在最前面。
由於字段的取值總是朝一個方向增長,新記錄總是存放在索引的最后一個葉頁中,從而不斷地引起該葉頁的訪問競爭、新葉頁的分配、中間分支頁的拆分。此外,如果所建索引是聚集索引,表中數據按照索引的排列順序存放,所有的插入操作都集中在最后一個數據頁上進行,從而引起插入“熱點”。
(4)對復合索引,按照字段在查詢條件中出現的頻度建立索引。
在復合索引中,記錄首先按照第一個字段排序。對於在第一個字段上取值相同的記錄,系統再按照第二個字段的取值排序,以此類推。因此只有復合索引的第一個字段出現在查詢條件中,該索引才可能被使用。
因此將應用頻度高的字段,放置在復合索引的前面,會使系統最大可能地使用此索引,發揮索引的作用。
(5)刪除不再使用,或者很少被使用的索引。
概要
什么是單一索引,什么又是復合索引呢? 何時新建復合索引,復合索引又需要注意些什么呢?本篇文章主要是對網上一些討論的總結。
一.概念
單一索引是指索引列為一列的情況,即新建索引的語句只實施在一列上。
用戶可以在多個列上建立索引,這種索引叫做復合索引(組合索引)。復合索引的創建方法與創建單一索引的方法完全一樣。但復合索引在數據庫操作期間所需的開銷更小,可以代替多個單一索引。當表的行數遠遠大於索引鍵的數目時,使用這種方式可以明顯加快表的查詢速度。
同時有兩個概念叫做窄索引和寬索引,窄索引是指索引列為1-2列的索引,如果不特殊說明的話一般是指單一索引。寬索引也就是索引列超過2列的索引。
設計索引的一個重要原則就是能用窄索引不用寬索引,因為窄索引往往比組合索引更有效。擁有更多的窄索引,將給優化程序提供更多的選擇余地,這通常有助於提高性能。
二.使用
創建索引
create index idx1 on table1(col1,col2,col3)
查詢
select * from table1 where col1= A and col2= B and col3 = C
這時候查詢優化器,不再掃描表了,而是直接的從索引中拿數據,因為索引中有這些數據,這叫覆蓋式查詢,這樣的查詢速度非常快。
三.注意事項
1.何時使用復合索引
在where條件中字段用索引,如果用多字段就用復合索引。一般在select的字段不要建什么索引(如果是要查詢select col1 ,col2, col3 from mytable,就不需要上面的索引了)。根據where條件建索引是極其重要的一個原則。注意不要過多用索引,否則對表更新的效率有很大的影響,因為在操作表的時候要化大量時間花在創建索引中.
2.對於復合索引,在查詢使用時,最好將條件順序按找索引的順序,這樣效率最高。如:
IDX1:create index idx1 on table1(col2,col3,col5)
select * from table1 where col2=A and col3=B and col5=D
如果是"select * from table1 where col3=B and col2=A and col5=D"
或者是"select * from table1 where col3=B"將不會使用索引,或者效果不明顯
3.復合索引會替代單一索引么?
很多人認為只要把任何字段加進聚集索引,就能提高查詢速度,也有人感到迷惑:如果把復合的聚集索引字段分開查詢,那么查詢速度會減慢嗎?帶着這個問題,我們來看一下以下的查詢速度(結果集都是25萬條數據):(日期列fariqi首先排在復合聚集索引的起始列,用戶名neibuyonghu排在后列)
IDX1:create index idx1 on Tgongwen(fariqi,neibuyonghu)
(1)select gid,fariqi,neibuyonghu,title from Tgongwen
where fariqi>'2004-5-5'
查詢速度:2513毫秒
(2)select gid,fariqi,neibuyonghu,title from Tgongwen
where fariqi>'2004-5-5' and neibuyonghu='辦公室'
查詢速度:2516毫秒
(3)select gid,fariqi,neibuyonghu,title from Tgongwen
where neibuyonghu='辦公室'
查詢速度:60280毫秒
從以上試驗中,我們可以看到如果僅用聚集索引的起始列作為查詢條件和同時用到復合聚集索引的全部列的查詢速度是幾乎一樣的,甚至比用上全部的復合索引列還要略快(在查詢結果集數目一樣的情況下);而如果僅用復合聚集索引的非起始列作為查詢條件的話,這個索引是不起任何作用的。當然,語句1、2的查詢速度一樣是因為查詢的條目數一樣,如果復合索引的所有列都用上,而且查詢結果少的話,這樣就會形成“索引覆蓋”,因而性能可以達到最優。同時,請記住:無論您是否經常使用聚合索引的其他列,但其前導列一定要是使用最頻繁的列。
[參考: 查詢優化及分頁算法方案 http://blog.csdn.net/chiefsailor/archive/2007/05/28/1628339.aspx]
4.需要在同一列上同時建單一索引和復合索引么?
試驗: sysbase 5.0 表table1 字段:col1,col2,col3
試驗步驟:
(1)建立索引idx1 on col1
執行select * from table1 where col1=A 使用idx1
執行select * from table1 where col1=A and col2=B 也使用idx1
(2)刪除索引idx1,然后建立idx2 on (col1,col2)復合索引
執行以上兩個查詢,也都使用idx2
(3)如果兩個索引idx1,idx2都存在
並不是 where col1='A'用idx1;where col1=A and col2=B 用idx2。
其查詢優化器使用其中一個以前常用索引。要么都用idx1,要么都用idx2.
由此可見,
(1)對一張表來說,如果有一個復合索引 on (col1,col2),就沒有必要同時建立一個單索引 on col1。
(2)如果查詢條件需要,可以在已有單索引 on col1的情況下,添加復合索引on (col1,col2),對於效率有一定的提高。
(3)同時建立多字段(包含5、6個字段)的復合索引沒有特別多的好處,相對而言,建立多個窄字段(僅包含一個,或頂多2個字段)的索引可以達到更好的效率和靈活性。
5. 一定需要覆蓋性查詢么?
通常最好不要采用一個強調完全覆蓋查詢的策略。如果Select子句中的所有列都被一個非群集索引覆蓋,優化程序會識別出這一點,並提供很好的性能。不過,這通常會導致索引過寬,並會過度依賴於優化程序使用該策略的可能性。通常,是用數量更多的窄索引,這對於大量查詢來說可以提供更好的性能。