1. 程式人生 > >mysql_建立索引的優缺點&效能優化

mysql_建立索引的優缺點&效能優化

建立索引的優缺點:

為什麼要建立索引呢?

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

        也許會有人要問:增加索引有如此多的優點,為什麼不對錶中的每一個列建立一個索引呢?這種想法固然有其合理性,然而也有其片面性。雖然,索引有許多優點, 但是,為表中的每一個列都增加索引,是非常不明智的。

       這是因為,增加索引也有許多不利的一個方面:

        第一、建立索引和維護索引要耗費時間,這種時間隨著資料量的增加而增加。 

        第二、索引需要佔物理空間,除了資料表佔資料空間之外,每一個索引還要佔一定的物理空間。如果要建立聚簇索引,那麼需要的空間就會更大。 

        第三、當對錶中的資料進行增加、刪除和修改的時候,索引也要動態的維護,這樣就降低了資料的維護速度。

 

什麼樣的欄位適合建立索引:

 索引是建立在資料庫表中的某些列的上面。因此,在建立索引的時候,應該仔細考慮在哪些列上可以建立索引,在哪些列上不能建立索引。

       一般來說,應該在這些列上建立索引,例如:

       第一、在經常需要搜尋的列上,可以加快搜索的速度; 

       第二、在作為主鍵的列上,強制該列的唯一性和組織表中資料的排列結構; 

       第三、在經常用在連線的列上,這些列主要是一些外來鍵,可以加快連線的速度; 

       第四、在經常需要根據範圍進行搜尋的列上建立索引,因為索引已經排序,其指定的範圍是連續的; 

       第五、在經常需要排序的列上建立索引,因為索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間; 

       第六、在經常使用在WHERE子句中的列上面建立索引,加快條件的判斷速度。

     

       建立索引,一般按照select的where條件來建立,比如: select的條件是where f1 and f2,那麼如果我們在欄位f1或欄位f2上簡歷索引是沒有用的,只有在欄位f1和f2上同時建立索引才有用等。

 

什麼樣的欄位不適合建立索引:

同樣,對於有些列不應該建立索引。一般來說,不應該建立索引的的這些列具有下列特點:

 

第一,對於那些在查詢中很少使用或者參考的列不應該建立索引。這是因為,既然這些列很少使用到,因此有索引或者無索引,

並不能提高查詢速度。相反,由於增加了索引,反而降低了系統的維護速度和增大了空間需求。 
       第二,對於那些只有很少資料值的列也不應該增加索引。這是因為,由於這些列的取值很少,例如人事表的性別列,

在查詢的結果中,結果集的資料行佔了表中資料行的很大比 例,即需要在表中搜索的資料行的比例很大。

增加索引,並不能明顯加快檢索速度。 
       第三,對於那些定義為text, image和bit資料型別的列不應該增加索引。這是因為,這些列的資料量要麼相當大,要麼取值很少。 
        第四,當修改效能遠遠大於檢索效能時,不應該建立索 引。這是因為,修改效能和檢索效能是互相矛盾的。

當增加索引時,會提高檢索效能,但是會降低修改效能。當減少索引時,會提高修改效能,降低檢索效能。

因此,當修改效能遠遠大於檢索效能時,不應該建立索引。


建立索引的方法::

1、建立索引,例如 create index <索引的名字> on table_name (列的列表); 
      2、修改表,例如 alter table table_name add index[索引的名字] (列的列表); 
      3、建立表的時候指定索引,例如create table table_name ( [...], INDEX [索引的名字] (列的列表) );

 

查看錶中索引的方法:

show index from table_name; 檢視索引

 

 

索引的型別及建立例子::

1.PRIMARY KEY (主鍵索引)

MySQL> alter table table_name add primary key ( `column` )

 

2.UNIQUE 或 UNIQUE KEY (唯一索引)

mysql> alter table table_name add unique (`column`)


     3.FULLTEXT (全文索引)
     mysql> alter table table_name add fulltext (`column` )

     4.INDEX (普通索引)
     mysql> alter table table_name add index index_name ( `column` )

5.多列索引 (聚簇索引)
      mysql> alter table `table_name` add index index_name ( `column1`, `column2`, `column3` )


       修改表中的索引:

       alter table tablename drop primary key,add primary key(fileda,filedb)

 

 

------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

1.查詢的模糊匹配

儘量避免在一個複雜查詢裡面使用 LIKE '%parm1%'—— 紅色標識位置的百分號會導致相關列的索引無法使用,最好不要用.

解決辦法:

其實只需要對該指令碼略做改進,查詢速度便會提高近百倍。改進方法如下:

a、修改前臺程式——把查詢條件的供應商名稱一欄由原來的文字輸入改為下拉列表,使用者模糊輸入供應商名稱時,直接在前臺就幫忙定位到具體的供應商,這樣在呼叫後臺程式時,這列就可以直接用等於來關聯了。

b、直接修改後臺——根據輸入條件,先查出符合條件的供應商,並把相關記錄儲存在一個臨時表裡頭,然後再用臨時表去做複雜關聯

2.索引問題

在做效能跟蹤分析過程中,經常發現有不少後臺程式的效能問題是因為缺少合適索引造成的,有些表甚至一個索引都沒有。這種情況往往都是因為在設計表時,沒去定義索引,而開發初期,由於表記錄很少,索引建立與否,可能對效能沒啥影響,開發人員因此也未多加重視。然一旦程式釋出到生產環境,隨著時間的推移,表記錄越來越多

這時缺少索引,對效能的影響便會越來越大了。

這個問題需要資料庫設計人員和開發人員共同關注

法則:不要在建立的索引的資料列上進行下列操作:

◆避免對索引欄位進行計算操作

◆避免在索引欄位上使用not,<>,!=

◆避免在索引列上使用IS NULL和IS NOT NULL

◆避免在索引列上出現數據型別轉換

◆避免在索引欄位上使用函式

◆避免建立索引的列中使用空值。

3.複雜操作

部分UPDATE、SELECT 語句 寫得很複雜(經常巢狀多級子查詢)——可以考慮適當拆成幾步,先生成一些臨時資料表,再進行關聯操作

4.update

同一個表的修改在一個過程裡出現好幾十次,如:

update table1
set col1=...
where col2=...;
update table1
set col1=...
where col2=...
......

 

象這類指令碼其實可以很簡單就整合在一個UPDATE語句來完成(前些時候在協助xxx專案做效能問題分析時就發現存在這種情況)

5.在可以使用UNION ALL的語句裡,使用了UNION

UNION 因為會將各查詢子集的記錄做比較,故比起UNION ALL ,通常速度都會慢上許多。一般來說,如果使用UNION ALL能滿足要求的話,務必使用UNION ALL。還有一種情況大家可能會忽略掉,就是雖然要求幾個子集的並集需要過濾掉重複記錄,但由於指令碼的特殊性,不可能存在重複記錄,這時便應該使用UNION ALL,如xx模組的某個查詢程式就曾經存在這種情況,見,由於語句的特殊性,在這個指令碼中幾個子集的記錄絕對不可能重複,故可以改用UNION ALL)

6.在WHERE 語句中,儘量避免對索引欄位進行計算操作

這個常識相信絕大部分開發人員都應該知道,但仍有不少人這麼使用,我想其中一個最主要的原因可能是為了編寫寫簡單而損害了效能,那就不可取了

9月份在對XX系統做效能分析時發現,有大量的後臺程式存在類似用法,如:

 

......
where trunc(create_date)=trunc(:date1)

 

雖然已對create_date 欄位建了索引,但由於加了TRUNC,使得索引無法用上。此處正確的寫法應該是

 

where create_date>=trunc(:date1) and create_date<trunc(:date1)+1< pre="">

或者是

 

where create_date between trunc(:date1) and trunc(:date1)+1-1/(24*60*60)

 

注意:因between 的範圍是個閉區間(greater than or equal to low value and less than or equal to high value.),

故嚴格意義上應該再減去一個趨於0的小數,這裡暫且設定成減去1秒(1/(24*60*60)),如果不要求這麼精確的話,可以略掉這步。

7.對Where 語句的法則

7.1 避免在WHERE子句中使用in,not  in,or 或者having

可以使用 exist 和not exist代替 in和not in。

可以使用錶鏈接代替 exist。Having可以用where代替,如果無法代替可以分兩步處理。

例子

SELECT *  FROM ORDERS WHERE CUSTOMER_NAME NOT IN 
(SELECT CUSTOMER_NAME FROM CUSTOMER)

 

優化

SELECT *  FROM ORDERS WHERE CUSTOMER_NAME not exist 
(SELECT CUSTOMER_NAME FROM CUSTOMER)

 

7.2 不要以字元格式宣告數字,要以數字格式宣告字元值。(日期同樣)否則會使索引無效,產生全表掃描。

例子使用:

SELECT emp.ename, emp.job FROM emp WHERE emp.empno = 7369;
不要使用:SELECT emp.ename, emp.job FROM emp WHERE emp.empno = ‘7369’

 

8.對Select語句的法則

在應用程式、包和過程中限制使用select * from table這種方式。看下面例子

 

使用SELECT empno,ename,category FROM emp WHERE empno = '7369‘
而不要使用SELECT * FROM emp WHERE empno = '7369'

 

9. 排序

避免使用耗費資源的操作,帶有DISTINCT,UNION,MINUS,INTERSECT,ORDER BY的SQL語句會啟動SQL引擎 執行,耗費資源的排序(SORT)功能. DISTINCT需要一次排序操作, 而其他的至少需要執行兩次排序

10.臨時表

慎重使用臨時表可以極大的提高系統性能