##概述
作爲一個高級程序員,不僅要熟練使用sql語句,更應該使用高效的sql語句。
本篇blog講解的內容主要包括:
- 索引的使用。
- 執行計劃分析。
- sql優化常見案例分析。
##索引
一,什麼是索引
索引的作用只有一個,提高查找效率。
如下面sql語句:
select name from person where age = 16;
在正常情況下,MySql是從第一條數依次遍歷,直到讀完整個表才能得到所有age等於16的數據。
如果對age字段建立索引,MySql會維護一個索引表,索引表中存儲不同age與數據對對應關係,當查找age等於16的數據時會先在索引表中找到age等於16對應的數據id,然後直接根據數據id從數據表中需要的數據。這就類似於新華字典中的拼音查字法,先從拼音序列中找出這個字在哪一頁,然後直接去那一頁去找,避免翻遍整個字典,很大的提供了查找效率。
二,索引的利弊分析
上面說到創建索引會很大的提高查找效率,但索引也有弊端。
創建索引系統會自動維護一個索引表,每當數據增加,更新,刪除時都需要更改索引表,所以創建索引會降低增加,更新,刪除的效率。
三,創建索引的原則
創建索引針對的對象是字段,所以我們要找出適合創建索引的字段。
建議創建索引的列:
- 定義主鍵的數據列一定要建立索引。
- 定義有外鍵的數據列一定要建立索引。
- 對於經常查詢的數據列最好建立索引。
- 對於需要在指定範圍內的快速或頻繁查詢的數據列最好創建索引;
- 經常用在WHERE句中的數據列最好創建索引。
- 經常出現在關鍵字order by、group by、distinct後面的字段,建立索引。如果建立的是複合索引,索引的字段順序要和這些關鍵字後面的字段順序一致,否則索引不會被使用。
不建議創建索引的列:
- 對於那些查詢中很少涉及的列,重複值比較多的列不要建立索引。
- 對於定義爲text、image和bit的數據類型的列不要建立索引。
- 對於經常存取的列避免建立索引
- 限制表上的索引數目。對一個存在大量更新操作的表,所建索引的數目一般不要超過3個,最多不要超過5個。索引雖說提高了訪問速度,但太多索引會影響數據的更新操作。
- 對複合索引,按照字段在查詢條件中出現的頻度建立索引。在複合索引中,記錄首先按照第一個字段排序。對於在第一個字段上取值相同的記錄,系統再按照第二個字段的取值排序,以此類推。因此只有複合索引的第一個字段出現在查詢條件中,該索引纔可能被使用,因此將應用頻度高的字段,放置在複合索引的前面,會使系統最大可能地使用此索引,發揮索引的作用。
注:具體怎麼哪些列可以創建索引,哪些列不建議創建索引,需要具體情況具體分析,需要開發中慢慢積累經驗。
四,創建索引
索引分爲單索引和組合索引。但索引是給一個字段創建的索引,組合索引是給多個字段創建的索引。
比如給person表中的age字段創建索引的sql是:
ALTER TABLE `xia`.`person` ADD INDEX(`age`) USING BTREE COMMENT '給age創建索引';
navicate也支持創建索引的圖形化操作,如下:
##執行計劃
執行計劃就是分析執行某個sql語句的詳細細節。
查看某個sql語句的執行計劃很容易,只有在sql語句前添加EXPLAIN關鍵詞即可。如下:
EXPLAIN select * from person WHERE age = 16 and id > 0;
執行結果如下:
說明:
- type:表示執行sql使用了哪種類型。類型的種類從好到差依次是:const、eq_reg、ref、range、indexhe和ALL。
- possible_keys:可能使用到的索引。此時有兩個:PRIMARY,index_age。其中PRIMARY是主鍵,index_age是自己創建的索引。
- key:實際用到的索引。
- key_len:使用索引的長度,該值越小越好。
- ref:
- rows:數據遍歷的行數,數值越小越好。
總結:要學會且有意識的多使用執行計劃,查看每一個sql語句的執行計劃,儘量優化sql,提高項目的執行效率。
##sql優化具體分析
sql優化主要針對查詢sql進行優化,因爲只有查詢語句纔會出現掃描全表的情況。隨着數據量的增大,掃描全表會非常耗時,優化sql的目的是儘量掃描少的數據量。
具體細節如下:
1,儘量給字段設置默認值,避免字段值爲null情況。
如果字段是int類型的age,首先給age創建索引時null不會參與創建索引。where age=0比where age is null效率高。
2,在where語句中少使用or,使用or將不使用索引。
如select name where age = 16 or age = 20
可以寫成:
select name where age = 16 union all select name where age = 20
3,在where語句中避免使用in,
如select * from score where student_id in (select id from student where name='guoxiang')
可以寫成:
select * from score sc where exists (select 1 from student st where st.name='guoxiang' and st.id = sc.student_id)