性能調優前提:無監控不調優,對於mysql性能的監控前幾天有文章提到過,有興趣的朋友能夠去看一下html
一、咱們在監控圖表中關注的性能指標大概有這麼幾個:CPU、內存、鏈接數、io讀寫時間、io操做時間、慢查詢、系統平均負載以及memoryOvermysql
二、介紹下Grafana模板中各性能指標的意思sql
這個是Mysql數據庫的鏈接數數據庫
這個圖標表示了慢查詢數組
上圖就是Mysql數據庫的緩存區,展現了最大緩存以及已使用緩存等數據緩存
三、性能分析網絡
通常在產生Mysql瓶頸的時候每每伴隨着的是CPU使用率急速上升,須要top看一下是哪一個線程佔據了大量的CPU資源,若是發現Mysql進程佔用較高,那麼基本能夠判斷是Mysql數據庫出現了問題。併發
接下來就是對問題具體的分析和定位。函數
對於數據庫的操做基本上就是大量的查詢,會致使數據庫出現性能問題。對有問題的場景使用Jmeter模擬場景進行併發,並觀察Grafana的圖表。性能
Mysql的幾個問題基本上就是:一、緩存區較小,大量查詢致使了緩存區溢出,使用io進行讀寫,衆所周知,io的讀寫速度遠遠比內存讀寫速度要慢得多。
二、sql語句問題,致使mysql數據庫出現瓶頸的查詢語句類型不少,最後會給你們列舉一些。
那麼怎麼定位到這些問題呢?
(1)在負載測試中,經過Grafana圖表觀察Memory Over這個圖表,若是發現佔用基本佔滿所分配給Mysql數據庫緩存區的內存,而後IO讀寫時間很是長,讀寫頻率很是高,那基本上是能夠判斷是緩存區較小致使的問題。(這個問題已經不多出現了)
(2)判斷慢查詢:在mysql數據庫的配置文件中找到
log_output=file,table #二選 1 或者 2 個都選 slow_query_log=on slow_query_log_file = /tmp/mysql-slow.log long_query_time = 1 #設置如何判斷慢查詢,這邊設置超過1s就算慢查詢
#使用完記得關閉
重啓Mysql數據庫
在Grafana圖表中若是看到慢查詢的時間超過1s時,基本判斷爲存在慢查詢。
登入數據庫運行命令
select * from mysql.slow_log;#查看慢查詢表數據
運行完這條命令後,能夠查看到全部超過1s的查詢語句,這個時候複製這條語句到查詢輸入框中,選中右鍵點擊解釋。
type列,鏈接類型。一個好的sql語句至少要達到range級別。杜絕出現all級別
key列,使用到的索引名。若是沒有選擇索引,值是NULL。能夠採起強制索引方式
key_len列,索引長度
rows列,掃描行數。該值是個預估值
extra列,詳細說明。注意常見的不太友好的值有:Using filesort, Using temporary
MySQL對於IN作了相應的優化,即將IN中的常量所有存儲在一個數組裏面,並且這個數組是排好序的。可是若是數值較多,產生的消耗也是比較大的。再例如:select id from t where num in(1,2,3) 對於連續的數值,能用 between 就不要用 in 了;再或者使用鏈接來替換。
SELECT *增長不少沒必要要的消耗(cpu、io、內存、網絡帶寬);增長了使用覆蓋索引的可能性;當表結構發生改變時,前斷也須要更新。因此要求直接在select後面接上字段名。
這是爲了使EXPLAIN中type列達到const類型
or兩邊的字段中,若是有一個不是索引字段,而其餘條件也不是索引字段,會形成該查詢不走索引的狀況。不少時候使用 union all 或者是union(必要的時候)的方式來代替「or」會獲得更好的效果
select * from 表A where id in (select id from 表B)
上面sql語句至關於
select * from 表A where exists(select * from 表B where 表B.id=表A.id)
區分in和exists主要是形成了驅動順序的改變(這是性能變化的關鍵),若是是exists,那麼之外層表爲驅動表,先被訪問,若是是IN,那麼先執行子查詢。因此IN適合於外表大而內表小的狀況;EXISTS適合於外表小而內表大的狀況。
關於not in和not exists,推薦使用not exists,不只僅是效率問題,not in可能存在邏輯問題。如何高效的寫出一個替代not exists的sql語句?
原sql語句
select colname … from A表 where a.id not in (select b.id from B表)
高效的sql語句
select colname … from A表 Left join B表 on where a.id = b.id where b.id is null
在一些用戶選擇頁面中,可能一些用戶選擇的時間範圍過大,形成查詢緩慢。主要的緣由是掃描行數過多。這個時候能夠經過程序,分段進行查詢,循環遍歷,將結果合併處理進行展現
對於null的判斷會致使引擎放棄使用索引而進行全表掃描。
例如LIKE 「%name」或者LIKE 「%name%」,這種查詢會致使索引失效而進行全表掃描。可是可使用LIKE 「name%」。
對於聯合索引來講,若是存在範圍查詢,好比between,>,<等條件時,會形成後面的索引字段失效。
type
訪問類型
ALL 掃描全表數據
index 遍歷索引
range 索引範圍查找
index_subquery 在子查詢中使用 ref
unique_subquery 在子查詢中使用 eq_ref
ref_or_null 對Null進行索引的優化的 ref
fulltext 使用全文索引
ref 使用非惟一索引查找數據
eq_ref 在join查詢中使用PRIMARY KEYorUNIQUE NOT NULL索引關聯。
const 使用主鍵或者惟一索引,且匹配的結果只有一條記錄。
system const 鏈接類型的特例,查詢的表爲系統表。
性能從好到差依次爲:
system,const,eq_ref,ref,fulltext,ref_or_null,unique_subquery,index_subquery,range,index_merge,index,ALL,除了ALL以外,其餘的type均可以使用到索引,除了index_merge以外,其餘的type只能夠用到一個索引。
可能使用的索引,注意不必定會使用。查詢涉及到的字段上若存在索引,則該索引將被列出來。當該列爲 NULL時就要考慮當前的SQL是否須要優化了。
顯示MySQL在查詢中實際使用的索引,若沒有使用索引,顯示爲NULL。
TIPS:查詢中若使用了覆蓋索引(覆蓋索引:索引的數據覆蓋了須要查詢的全部數據),則該索引僅出如今key列表中
一、SQL語句不要寫的太複雜。
一個SQL語句要儘可能簡單,不要嵌套太多層。
二、使用like的時候要注意是否會致使全表掃
三、儘可能避免使用!=或<>操做符
在where語句中使用!=或<>,引擎將放棄使用索引而進行全表掃描。
四、儘可能避免使用 or 來鏈接條件
在 where 子句中使用 or 來鏈接條件,引擎將放棄使用索引而進行全表掃描。
五、儘可能避免使用in和not in
在 where 子句中使用 in和not in,引擎將放棄使用索引而進行全表掃描。
六、儘可能避免使用表達式、函數等操做做爲查詢條件
七、儘可能避免大事務操做,提升系統併發能力。
八、任何地方都不要使用 select * from t ,用具體的字段列表代替「*」,不要返回用不到的任何字段。
九、儘可能使用數字型字段,若只含數值信息的字段儘可能不要設計爲字符型,這會下降查詢和鏈接的性能,並會增長存儲開銷。
十、索引並非越多越好,索引當然能夠提升相應的 select 的效率,但同時也下降了 insert 及 update 的效率
十一、並非全部索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重複時,SQL查詢可能不會去利用索引
原文出處:https://www.cnblogs.com/congyiwei/p/12404261.html