sql優化總結--博客
第一次本身寫博客,之後要堅持每掌握一個技能點,就要寫一篇博客出來,作一個不知足於一個
只會寫if...else的程序員。
最近三個月入職了一家新的公司,作的是CRM系統,將公司多個平臺的數據同步到CRM,進行
查詢,統計和彙總。因爲數據量比較龐大,大部分表數據上百萬,甚至有的表數據上千萬。因此
在系統中作sql優化比較多,特此寫一篇博客總結一下關於sql優化方面的經驗。
--致使查詢緩慢的緣由
一、數據量過大
二、表設計不合理
三、sql語句寫得很差
四、沒有合理使用索引
-- 針對SQL語句的優化
一、查詢語句中不要使用 *
二、儘可能減小子查詢,使用關聯查詢(left join,right join,inner join)替代
三、減小使用IN或者NOT IN ,使用exists,not exists或者關聯查詢語句替代
四、or 的查詢儘可能用 union或者union all 代替
(在確認沒有重複數據或者不用剔除重複數據時,union all會更好)
五、合理的增長冗餘的字段(減小表的聯接查詢)
六、增長中間表進行優化(這個主要是在統計報表的場景,
後臺開定時任務將數據先統計好,儘可能不要在查詢的時候去統計)
七、建表的時候能使用數字類型的字段就使用數字類型(type,status...),數字類型的字段做爲條件查詢比字符串的快
八、那些能夠過濾掉最大數量記錄的條件必須寫在WHERE子句的最末尾
-- 索引優化
若是針對sql語句已經沒啥能夠優化的,那咱們就要考慮加索引了。
--說索引前先說說explain查看sql的執行計劃
1 id
SELECT識別符。這是select查詢序列號。這個不重要
2 select_type
表示查詢中每一個select子句的類型(簡單OR複雜)
有如下幾種值:
1 simple
查詢中不包含查詢或者UNION(聯合查詢)
2 PRIMARY
查詢中若包含任何複雜的子部分,最外層查詢則被標記爲:PRIMARY
3 UNION
表示鏈接查詢的第2個或後面的查詢語句。
4 DEPENDENT UNION
UNION 中的第二個或者後面的select語句,取決於外面的查詢
5 UNION RESULT
鏈接查詢的結果
6 SUBQUERY
子查詢中的第一個select語句
7 DEPENDENT SUBQUERY
子查詢中的第一個select語句,取決於外面的查詢
8 DERIVED
select(from子句的子查詢)
3 table 表示查詢的表
4 type
表示表的鏈接類型
如下的鏈接類型的順序是從最佳類型到最差類型
1 syste
表僅有一行,這是const類型的特例,平時不會出現
2 const
數據表最多隻有一個匹配行,由於只匹配一行數據,因此很快,經常使用於PRIMARY KEY
或者UNIQUE查詢,可理解爲是最優化的。
3 eq_ref
mysql手冊是這樣說的: 對於每一個來自前面的表的行組合,從該表中讀取一行。
這多是最好的聯接類型,除了const類型。他用在一個索引的全部部分被聯接使用而且而且索引是UNIQUE或PRIMARY KEY eq_ref能夠用於使用=比較帶索引的列。
4 ref
查詢條件索引既不是UNIQUE 也不是PRIMARY KEY 的狀況,ref可用於=或<或>操做符的帶索引的列。
5 ref_or_null
該聯接類型如同ref,可是添加了Mysql能夠專門搜索包含null值的行,在解決子查詢中常用該聯接類型的優化。
以上這五種狀況都是很理想的索引使用狀況。
6 index
該鏈接類型與ALL相同,除了只有索引樹被掃描。這一般比ALL快,由於索引文件一般比數據文件小。
7 ALL
對於每一個來自先前的表的行組合,進行完整的表掃描。
5 possible_key
指出Mysql能使用哪一個索引在該表中找到行。
若是該列爲NULL 說明沒有使用索引,能夠對該列建立索引來提升性能
6 Key
顯示mysql實際決定使用的索引,若是沒有選擇索引,鍵是null
能夠強制使用索引或者忽略索引:
強制使用索引:USE index(列名)
忽略使用索引:IGNORE INDEX(列名)
7 key_len
顯示mysql決定使用的鍵長度。若是鍵是NULL則長度爲NULL。
注意:key_len 是肯定了mysql將實際使用的索引長度
8 ref
顯示使用哪一個列或常數與key一塊兒從表中選擇行
9 rows
顯示mysql認爲它執行查詢時必須檢查的行數
10 extra
關於MYSQL如何解析查詢的額外信息。Using temporary和Using filesort,意思MYSQL根本不能使用索引,結果是檢索會很慢
說明:extra列返回的描述的意義
Distinct :一旦mysql找到了與行相聯合匹配的行,就再也不搜索了。
Not exists :mysql優化了LEFT JOIN,一旦它找到了匹配LEFT JOIN標準的行,就再也不搜索了。
Range checked for each Record(index map:#) :沒有找到理想的索引,所以對從前面表中來的每個行組合,mysql檢查使用哪一個索引,並用它來從表中返回行。這是使用索引的最慢的鏈接之一。
Using filesort :看到這個的時候,查詢就須要優化了。mysql須要進行額外的步驟來發現如何對返回的行排序。它根據鏈接類型以及存儲排序鍵值和匹配條件的所有行的行指針來排序所有行。
Using index :列數據是從僅僅使用了索引中的信息而沒有讀取實際的行動的表返回的,這發生在對錶的所有的請求列都是同一個索引的部分的時候。
Using temporary :看到這個的時候,查詢須要優化了。這裏,mysql須要建立一個臨時表來存儲結果,這一般發生在對不一樣的列集進行ORDER BY上,而不是GROUP BY上。
Where used :使用了WHERE從句來限制哪些行將與下一張表匹配或者是返回給用戶。若是不想返回表中的所有行,而且鏈接類型ALL或index,這就會發生,或者是查詢有問題。
使用explain查看sql執行計劃後,咱們主要先看下type屬性,表示鏈接的類型,若是是ALL這種那就須要優化了,
再看下possible_key屬性,表示可使用的索引,若是沒有則爲null,key屬性表示mysql實際決定使用的索引,若是沒有選擇索引,鍵是null,
rows 表示mysql認爲它執行查詢時必須檢查的行數,行數越多效率越低。
--索引類型
主鍵索引,惟一索引,組合索引,普通索引
--什麼是索引
數據庫索引是數據庫管理系統中的一個排序的數據結構,以協助快速查詢,更新數據庫表中數據,索引的實現一般使用B樹(B-tree)以及其變種B+tree(一些高效率的算法)
--使用索引時有些不生效的狀況
一、使用like關鍵字模糊查詢時,% 放在前面索引不起做用,只有「%」不在第一個位置,索引纔會生效(like '%文'--索引不起做用)
二、使用聯合索引時,只有查詢條件中使用了這些字段中的第一個字段,索引纔會生效
三、使用OR關鍵字的查詢,查詢語句的查詢條件中只有OR關鍵字,且OR先後的兩個條件中的列都是索引時,索引纔會生效,不然索引不生效。
四、儘可能避免在where子句中使用!=或<>操做符,不然引擎將放棄使用索引而進行全表掃描。
五、對查詢進行優化,應儘可能避免全表掃描,首先應考慮在where以及order by涉及的列上創建索引。
六、應儘可能避免在 where 子句中對字段進行表達式操做,這將致使引擎放棄使用索引而進行全表掃描。如:
select id from t where num/2=100
應改成:
select id from t where num=100*2
七、儘可能避免在where子句中對字段進行函數操做,將致使引擎放棄使用索引而進行全表掃描。
八、不要在 where 子句中的「=」左邊進行函數、算術運算或其餘表達式運算,不然系統將可能沒法正確使用索引。
九、並非全部的索引對查詢都有效,sql是根據表中的數據來進行查詢優化的,當索引列有大量數據重複時,sql查詢不會去利用索引,如一表中有字段
sex,male,female幾乎個一半,那麼即便在sex上創建了索引也對查詢效率起不了做用。
十、索引並非越多越好,索引當然能夠提升相應的 select 的效率,但同時也下降了 insert 及 update 的效率,
由於 insert 或 update 時有可能會重建索引,因此怎樣建索引須要慎重考慮,視具體狀況而定。一個表的索引數最好不要超過6個,
若太多則應考慮一些不常使用到的列上建的索引是否有 必要。
十一、儘可能使用數字型字段,若只含數值信息的字段儘可能不要設計爲字符型,這會下降查詢和鏈接的性能,並會增長存儲開銷。
這是由於引擎在處理查詢和鏈接時會 逐個比較字符串中每個字符,而對於數字型而言只須要比較一次就夠了。
十二、mysql查詢只使用一個索引,所以若是where子句中已經使用了索引的話,那麼order by中的列是不會使用索引的。
所以數據庫默認排序能夠符合要求的狀況下不要使用排序操做,儘可能不要包含多個列的排序,若是須要最好給這些列建複合索引。
1三、order by 索引 ,不起做用的問題(除了主鍵索引以外):
一、 若是select 只查詢索引字段,order by 索引字段會用到索引,要否則就是全表排列; 二、若是有where 條件,好比where vtype=1 order by vtype asc . 這樣order by 也會用到索引!