1. 程式人生 > >資料庫索引介紹及使用

資料庫索引介紹及使用

一、索引的概念
        索引就是加快檢索表中資料的方法。資料庫的索引類似於書籍的索引。在書籍中,索引允許使用者不必翻閱完整個書就能迅速地找到所需要的資訊。在資料庫中,索引也允許資料庫程式迅速地找到表中的資料,而不必掃描整個資料庫。

二、索引的特點
    1.索引可以加快資料庫的檢索速度 
    2.索引降低了資料庫插入、修改、刪除等維護任務的速度 
    3.索引建立在表上,不能建立在檢視上 
    4.索引既可以直接建立,也可以間接建立 
    5.可以在優化隱藏中,使用索引 
    6.使用查詢處理器執行SQL語句,在一個表上,一次只能使用一個索引 
    7.其他

三、索引的優點
    1.建立唯一性索引,保證資料庫表中每一行資料的唯一性
    2.大大加快資料的檢索速度,這也是建立索引的最主要的原因
    3.加速表和表之間的連線,特別是在實現資料的參考完整性方面特別有意義。
    4.在使用分組和排序子句進行資料檢索時,同樣可以顯著減少查詢中分組和排序的時間。
    5.通過使用索引,可以在查詢的過程中使用優化隱藏器,提高系統的效能。

四、索引的缺點
    1.建立索引和維護索引要耗費時間,這種時間隨著資料量的增加而增加
    2.索引需要佔物理空間,除了資料表佔資料空間之外,每一個索引還要佔一定的物理空間,如果要建立聚簇索引,那麼需要的空間就會更大
    3.當對錶中的資料進行增加、刪除和修改的時候,索引也要動態的維護,降低了資料的維護速度

五、索引分類
    1.直接建立索引和間接建立索引
    直接建立索引: CREATE INDEX mycolumn_index ON mytable (myclumn)
    間接建立索引:定義主鍵約束或者唯一性鍵約束,可以間接建立索引
    2.普通索引和唯一性索引
    普通索引:CREATE INDEX mycolumn_index ON mytable (myclumn)
    唯一性索引:保證在索引列中的全部資料是唯一的,對聚簇索引和非聚簇索引都可以使用
    CREATE UNIQUE COUSTERED INDEX myclumn_cindex ON mytable(mycolumn)
    3.單個索引和複合索引
    單個索引:即非複合索引
    複合索引:又叫組合索引,在索引建立語句中同時包含多個欄位名,最多16個欄位
    CREATE INDEX name_index ON username(firstname,lastname)
    4.聚簇索引和非聚簇索引(聚集索引,群集索引)
   聚簇索引:物理索引,與基表的物理順序相同,資料值的順序總是按照順序排列
    CREATE CLUSTERED INDEX mycolumn_cindex ON mytable(mycolumn) WITH
    ALLOW_DUP_ROW(允許有重複記錄的聚簇索引)
   非聚簇索引:CREATE UNCLUSTERED INDEX mycolumn_cindex ON mytable(mycolumn)

六、索引的使用
   1.當欄位資料更新頻率較低,查詢使用頻率較高並且存在大量重複值是建議使用聚簇索引
    2.經常同時存取多列,且每列都含有重複值可考慮建立組合索引
    3.複合索引的前導列一定好控制好,否則無法起到索引的效果。如果查詢時前導列不在查詢條件中則該複合索引不會被使用。前導列一定是使用最頻繁的列
    4.多表操作在被實際執行前,查詢優化器會根據連線條件,列出幾組可能的連線方案並從中找出系統開銷最小的最佳方案。連線條件要充份考慮帶有索引的表、行數多的表;內外表的選擇可由公式:外層表中的匹配行數*內層表中每一次查詢的次數確定,乘積最小為最佳方案
    5.where子句中對列的任何操作結果都是在sql執行時逐列計算得到的,因此它不得不進行表搜尋,而沒有使用該列上面的索引;如果這些結果在查詢編譯時就能得到,那麼就可以被sql優化器優化,使用索引,避免表搜尋(例:select * from record where substring(card_no,1,4)=’5378’ 
&& select * from record where card_no like ’5378%’)任何對列的操作都將導致表掃描,它包括資料庫函式、計算表示式等等,查詢時要儘可能將操作移至等號右邊
    6.where條件中的’in’在邏輯上相當於’or’,所以語法分析器會將in ('0','1')轉化為column='0' or column='1'來執行。我們期望它會根據每個or子句分別查詢,再將結果相加,這樣可以利用column上的索引;但實際上它卻採用了"or策略",即先取出滿足每個or子句的行,存入臨時資料庫的工作表中,再建立唯一索引以去掉重複行,最後從這個臨時表中計算結果。因此,實際過程沒有利用column上索引,並且完成時間還要受tempdb資料庫效能的影響。in、or子句常會使用工作表,使索引失效;如果不產生大量重複值,可以考慮把子句拆開;拆開的子句中應該包含索引
    7.要善於使用儲存過程,它使sql變得更加靈活和高效 


索引使用原則:

1、使用索引來更快地遍歷表。 
預設情況下建立的索引是非群集索引,但有時它並不是最佳的。在非群集索引下,資料在物理上隨機存放在資料頁上。合理的索引設計要建立在 
對各種查詢的分析和預測上。一般來說: 
a.有大量重複值、且經常有範圍查詢( > ,< ,> =,< =)和order by、group by發生的列,可考 
慮建立群集索引; 
b.經常同時存取多列,且每列都含有重複值可考慮建立組合索引; 
c.組合索引要儘量使關鍵查詢形成索引覆蓋,其前導列一定是使用最頻繁的列。索引雖有助於提高效能但不是索引越多越好,恰好相反過多的索引會導致系統低效。使用者在表中每加進一個索引,維護索引集合就要做相應的更新工作。 
2、在海量查詢時儘量少用格式轉換。 
3、ORDER BY和GROPU BY使用ORDER BY和GROUP BY短語,任何一種索引都有助於SELECT的效能提高。 
7、任何對列的操作都將導致表掃描,它包括資料庫函式、計算表示式等等,查詢時要儘可能將操作移至等號右邊。 
4、IN、OR子句常會使用工作表,使索引失效。如果不產生大量重複值,可以考慮把子句拆開。拆開的子句中應該包含索引。

Sql的優化原則2: 
1、只要能滿足你的需求,應儘可能使用更小的資料型別:例如使用MEDIUMINT代替INT 
2、儘量把所有的列設定為NOT NULL,如果你要儲存NULL,手動去設定它,而不是把它設為預設值。 
3、儘量少用VARCHAR、TEXT、BLOB型別 
4、如果你的資料只有你所知的少量的幾個。最好使用ENUM型別 
5、正如graymice所講的那樣,建立索引。 
以下是我做的一個實驗,可以發現索引能極大地提高查詢的效率:

我有一個會員資訊表users,裡邊有37365條使用者記錄:

在不加索引的時候進行查詢: 
sql語句A: 
select * from users where username like ’%許%’; 
在Mysql-Front中的8次查詢時長為:1.40,0.54,0.54,0.54,0.53,0.55,0.54 共找到960條記錄

sql語句B: 
select * from users where username like ’許%’; 
在Mysql-Front中的8次查詢時長為:0.53,0.53,0.53,0.54,0.53,0.53,0.54,0.54 共找到836條記錄

sql語句C: 
select * from users where username like ’%許’; 
在Mysql-Front中的8次查詢時長為:0.51,0.51,0.52,0.52,0.51,0.51,0.52,0.51 共找到7條記錄

為username列新增索引: 
create index usernameindex on users(username(6));

再次查詢: 
sql語句A: 
select * from users where username like ’%許%’; 
在Mysql-Front中的8次查詢時長為:0.35,0.34,0.34,0.35,0.34,0.34,0.35,0.34 共找到960條記錄

sql語句B: 
select * from users where username like ’許%’; 
在Mysql-Front中的8次查詢時長為:0.06,0.07,0.07,0.07,0.07,0.07,0.06,0.06 共找到836條記錄

sql語句C: 
select * from users where username like ’%許’; 
在Mysql-Front中的8次查詢時長為:0.32,0.31,0.31,0.32,0.31,0.32,0.31,0.31 共找到7條記錄

在實驗過程中,我沒有另開任何程式,以上的資料說明在單表查詢中,建立索引的可以極大地提高查詢速度。 
另外要說的是如果建立了索引,對於like ’許%’型別的查詢,速度提升是最明顯的。因此,我們在寫sql語句的時候也儘量採用這種方式查詢。

對於多表查詢我們的優化原則是:

儘量將索引建立在:left join on/right join on ... +條件,的條件語句中所涉及的欄位上。

多表查詢比單表查詢更能體現索引的優勢。

6、索引的建立原則: 
如果一列的中資料的字首重複值很少,我們最好就只索引這個字首。Mysql支援這種索引。我在上面用到的索引方法就是對username最左邊的6個字元進行索引。索引越短,佔用的

磁碟空間越少,在檢索過程中花的時間也越少。這方法可以對最多左255個字元進行索引。

在很多場合,我們可以給建立多列資料建立索引。

索引應該建立在查詢條件中進行比較的欄位上,而不是建立在我們要找出來並且顯示的欄位上

7、限制索引的使用的避歸。
7.1  IN、OR子句常會使用工作表,使索引失效。
如果不產生大量重複值,可以考慮把子句拆開。拆開的子句中應該包含索引。這句話怎麼理解決,請舉個例子

例子如下: 
如果在fields1和fields2上同時建立了索引,fields1為主索引 
以下sql會用到索引 
select * from tablename1 where fields1=’value1’ and fields2=’value2’ 
以下sql不會用到索引 
select * from tablename1 where fields1=’value1’ or fields2=’value2’ 
7.2 使用IS NULL 或IS NOT NULL
         使用IS NULL 或IS NOT NULL同樣會限制索引的使用。因為NULL值並沒有被定義。在SQL語句中使用NULL會有很多的麻煩。因此建議開     發人員在建表時,把需要索引的列設成NOT NULL。如果被索引的列在某些行中存在NULL值,就不會使用這個索引(除非索引是一個位圖索引,關於點陣圖索引在稍後在詳細討論)。

7.3 使用函式
如果不使用基於函式的索引,那麼在SQL語句的WHERE子句中對存在索引的列使用函式時,會使優化器忽略掉這些索引。下面的查詢不會使用索引(只要它不是基於函式的索引)
   select empno,ename,deptno
          from   emp
          where  trunc(hiredate)='01-MAY-81';
          把上面的語句改成下面的語句,這樣就可以通過索引進行查詢。
          select empno,ename,deptno
          from   emp
          where  hiredate<(to_date('01-MAY-81')+0.9999);

7.4 比較不匹配的資料型別
比較不匹配的資料型別也是比較難於發現的效能問題之一。注意下面查詢的例子,account_number是一個VARCHAR2型別,在account_number欄位上有索引。下面的語句將執行全表掃描。
         select bank_name,address,city,state,zip
         from   banks
         where  account_number = 990354;
         Oracle可以自動把where子句變成to_number(account_number)=990354,這樣就限制了索引的使用,改成下面的查詢就可以使用索引:
         select bank_name,address,city,state,zip
         from   banks
         where  account_number ='990354';
     特別注意:不匹配的資料型別之間比較會讓Oracle自動限制索引的使用,即便對這個查詢執行Explain Plan也不能讓您明白為什麼做了一               次“全表掃描”。

補充: 
1.索引帶來查詢上的速度的大大提升,但索引也佔用了額外的硬碟空間(當然現在一般硬碟空間不成問題),而且往表中插入新記錄時索引也要隨著更新這也需要一定時間. 
有些表如果經常insert,而較少select,就不用加索引了.不然每次寫入資料都要重新改寫索引,花費時間; 
這個視實際情況而定,通常情況下索引是必需的. 
2.我在對查詢效率有懷疑的時候,一般是直接用Mysql的Explain來跟蹤查詢情況. 
你用Mysql-Front是通過時長來比較,我覺得如果從查詢時掃描欄位的次數來比較更精確一些.