原本應該先發這篇的,如今才發現漏掉了mysql
1.開發人員具有必定的SQL優化基本功ios
2.在開發階段,每條寫的SQL在測試環境看看他的執行計劃sql
3.上線後讓DBA收集查詢比較慢的SQL數據庫
4.經過explain工具和show profile 分析慢SQL,修改代碼,從新上線,從新收集。若是貴公司的DBA關係和你很好,在優化的時候能夠拉他一塊兒,多學點理論和經驗oracle
5.數據庫參數調優工具
6.操做系統調優測試
7.更換硬件設備優化
MySQL有專門負責SELECT的優化器模塊,根據先前收集到的統計信息,爲SQL生成一條它認爲最優的執行計劃,但該計劃不必定是DBA認爲最優的。也就是說它有可能根據錯誤的統計信息生成了自認爲合理的執行計劃。這種時候須要DBA介入,重建索引——》從新收集統計信息,這樣MySQL纔可能按照真正最優的方式運行,若是MySQL仍是不能生成想要的執行計劃,DBA還能夠固化執行計劃spa
使用top、free、iostat、vmstat命令查看機器的硬件資源負載狀況操作系統
執行計劃是MySQL對SQL的執行生成的一套優化策略,以效率爲首要目的,提高SQL執行的速度
能夠在MySQL中使用explain SQL或者desc SQL來生成執行計劃,如:
有了執行計劃能幹嗎?
1.查看錶的讀取順序
2.數據讀取操做的操做類型
3.那些索引能夠被使用
4.實際使用了那些索引
5.表之間的引用
6.每張表有多少行被優化器查詢
若是ID相同,執行順序由上而下;
若是ID不一樣,執行順序是ID越大越先執行,爲何喃,越早縮小結果集對整個執行越有效,由於過濾的數據量更少,IO次數越少,CPU消耗越低
若是ID相同與不一樣同時存在,則先執行ID大的,ID相同的則按照順序執行
其中的derived2中的2就是id=2
取值範圍
ID | select_type | |
---|---|---|
1 | simple | |
2 | primary | |
3 | subquery | |
4 | derived | |
5 | union | |
6 | union result |
用於指明這個SQL是一個什麼類型的查詢語句,簡單查詢、複合查詢、嵌套查詢
simple:
sql中不包含子查詢或union
primary:
查詢中若包含任何複雜的子查詢,則最外層就被標記爲primary
subquery:
在select或者where部分中包含的查詢就被稱爲子查詢
dependent subquery:
相關子查詢,MySQL遇到這種狀況,不會先將子查詢的結果集找出來再匹配,而是從外部表拿到每個關聯的值到子查詢表去找撈數據,不少同窗常用的in,不論是在oracle仍是mysql都不推薦使用in(subquery),可使用join來代替
derived:
在from部分包含的第一個完整查詢,其結果爲被放在臨時表,在執行計劃中被標記爲derived(衍生)
union:
在from部分union關鍵字後面的查詢都會被標記爲union
depentent union:
相關子查詢合併的結果集
union result:
在from部分全部查詢union的結果被標記爲union result
經過下圖能夠看到一個比較全的執行計劃
SQL:該SQL只是爲了演示執行計劃,不要去扣裏面的寫法是否合理
explain select * from (select * from tb_item a union select * from tb_item b union select * from tb_item c) d join tb_order_item b on d.id = b.item_id where d.id in( select id from tb_item a1 union select id from tb_item b1 union select id from tb_item c1 );
就是這一步使用到的表名字,多是實際的表名,也多是MySQL處理過程當中的中間表別名,如derivedxxx或者unionxxx
顯示查詢使用了什麼類型,最好的結果順序是system>>const>>eq_ref>>ref>>range>>index>>all,在實際的開發和生產維護中,可以作到eq_ref是最好,達到ref級別徹底OK,儘可能減小index和all兩種狀況出現。若是出現本身解決不了,找DBA或者你的項目經理幫忙
1.system
一張表只有一行記錄,實際系統中應該不多出現這種狀況,若是有我估計也是什麼配置,可是這種狀況徹底能夠寫到配置文件,或者ZK、REDIS中
2.const
表示經過索引一次就找到,好比
explain select * from tb_item_cat where id = 1;
id是表tb_item_cat的主鍵,因此id=1一次查詢只能找到一行記錄。不管條件如何,必需要返回一行,多行就不會是const類型
3.eq_ref
惟一索引掃描,對於每一個索引建,表中只有一條記錄與之匹配。常見於主鍵和UNIQUE索引,好比
explain select * from tb_item_cat a join tb_order_item b on a.id=b.item_id;
MySQL會先處理b表中的數據,而後b.item_id在a表中根據索引只能找到一行記錄,所以符合要求,是eq_ref類型
4.ref
依然走索引掃描,可是一個索引鍵會對應表中多行數據
explain select * from tb_item_cat a where a.parent_id=2;
由於parent_id和item_id是多對一的關係,所以查詢條件爲parent_id=2必然會返回多條記錄,符合上面的條件,是ref類型
5.range
走索引掃描,可是掃描的是索引的一段範圍,好比使用between, < , > ,in等關係運算符
explain select * from tb_item_cat a where a.parent_id in(2,3);
6.index
走索引掃描,可是掃描的整個索引,這種狀況比全表掃描會好一點,由於單個索引在磁盤所佔空間一段是比整個表要少不少
explain select parent_id from tb_item_cat
由於我想要查詢的返回結果集只有parent_id字段,而該字段所有在索引中就能找到,因此走索引全掃描徹底OK,不須要再去掃描表
7.all
最慘的掃描方式,速度最慢,若是你的執行計劃打出來有它出現必定要注意
explain select * from tb_item_cat
理論上可能用到的索引,好比一個列上有2個索引,主鍵和一個複合索引(包含主鍵列),那麼在這裏顯示的就會有這啷個索引名
執行時實際會用的索引
查詢條件長度,在不損失查詢精度的狀況下,能夠儘可能減小查詢條件長度
顯示被用於索引掃描的列或常量值
explain select * from tb_item_cat where id=1;
此時ref就是const
explain select * from tb_item_cat a join tb_order_item b on a.id = b.item_id
能夠看到使用數據庫mydb的表b的item_id列被用於索引的掃描
估算出來的可能被掃描出來的行
三大重要的額外信息,會在這裏顯示
using filesort
索引自己的排序沒有被使用到,MySQL會將數據作另外的排序,這樣將會很耗費時間。在實際生產中,若是真的出現這種狀況,而索引又沒有必要建立的話,你能夠將數據讀出來以後本身在代碼中進行排序
using temporary
使用臨時表來保存中間結果,若是常常出現這種狀況,計算會不斷的申請內存,耗費內存和CPU,形成數據庫吞吐量嚴重降低,應用沒法響應開始排隊,最終應用沒法響應客戶端請求
using index
它是一個很好的提示,說明你的SQL寫得很不錯,未來的執行效果會很好