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.臨時表
慎重使用臨時表可以極大的提高系統性能