MySQL佔用IO太高解決方案【轉】

一、日誌產生的性能影響:html

因爲日誌的記錄帶來的直接性能損耗就是數據庫系統中最爲昂貴的IO資源。MySQL的日誌包括錯誤日誌(ErrorLog),更新日誌(UpdateLog),二進制日誌(Binlog),查詢日誌(QueryLog),慢查詢日誌(SlowQueryLog)等。固然,更新日誌是老版本的MySQL纔有的,目前已經被二進制日誌替代。mysql

在默認狀況下,系統僅僅打開錯誤日誌,關閉了其餘全部日誌,以達到儘量減小IO損耗提升系統性能的目的。可是在通常稍微重要一點的實際應用場景中,都至少須要打開二進制日誌,由於這是MySQL不少存儲引擎進行增量備份的基礎,也是MySQL實現複製的基本條件。有時候爲了進一步的性能優化,定位執行較慢的SQL語句,不少系統也會打開慢查詢日誌來記錄執行時間超過特定數值(由咱們自行設置)的SQL語句。redis

通常狀況下,在生產系統中不多有系統會打開查詢日誌。由於查詢日誌打開以後會將MySQL中執行的每一條Query都記錄到日誌中,會該系統帶來比較大的IO負擔,而帶來的實際效益卻並非很是大。通常只有在開發測試環境中,爲了定位某些功能具體使用了哪些SQL語句的時候,纔會在短期段內打開該日誌來作相應的分析。因此,在MySQL系統中,會對性能產生影響的MySQL日誌(不包括各存儲引擎本身的日誌)主要就是Binlog了。sql

二、mysql內執行以下指令:數據庫

set global sync_binlog=500;緩存

當每進行500次事務提交以後,MySQL將進行一次fsync之類的磁盤同步指令來將binlog_cache中的數據強制寫入磁盤。安全

set global innodb_flush_log_at_trx_commit=2;性能優化

默認值1表明每一次事務提交或事務外的指令都須要把日誌寫入(flush)硬盤,這是很費時的。特別是使用電池供電緩存(Battery backed up cache)時。設置爲2表明不寫入硬盤而是寫入系統緩存。日誌仍然會每秒flush到硬盤,因此你通常不會丟失超過1-2秒的更新。設成0會更快一點,但安全方面比較差,即便MySQL掛了也可能會丟失事務的數據。而值設置爲2只會在整個操做系統宕機時纔可能丟數據。服務器

注:從新開機後,該指令失效。可在服務啓動時,設置如上兩項。性能


於臨時表致使IO太高

【問題現象】

線上mysql數據庫爆出一個慢查詢,DBA觀察發現,查詢時服務器IO飆升,IO佔用率達到100%, 執行時間長達7s左右。

SQL語句以下:

SELECT DISTINCT g.*, cp.name AS cp_name, c.name AS category_name, t.name AS type_name FROMgm_game g
LEFT JOIN gm_cp cp ON cp.id = g.cp_id AND cp.deleted = 0
LEFT JOIN gm_category c ON c.id = g.category_id AND c.deleted = 0 \
LEFT JOIN gm_type t ON t.id = g.type_id AND t.deleted = 0 WHERE g.deleted = 0 ORDER BY g.modify_time DESC LIMIT 20 ;
【問題分析】

使用explain查看執行計劃,結果以下:

mysql執行計劃

這條sql語句的問題其實仍是比較明顯的: 查詢了大量數據(包括數據條數、以及g.* ),而後使用臨時表order by,但最終又只返回了20條數據。

DBA觀察到的IO高,是由於sql語句生成了一個巨大的臨時表,內存放不下,因而所有拷貝到磁盤,致使IO飆升。

【優化方案】

優化的整體思路是拆分sql,將排序操做和查詢全部信息的操做分開。

第一條語句:查詢符合條件的數據,只須要查詢g.id便可

SELECT DISTINCT g.id FROM gm_game g
LEFT JOIN gm_cp cp ON cp.id = g.cp_id AND cp.deleted = 0
LEFT JOIN gm_category c ON c.id = g.category_id AND c.deleted = 0
LEFT JOIN gm_type t ON t.id = g.type_id AND t.deleted = 0
  WHERE g.deleted = 0 ORDER BY g.modify_time DESC LIMIT 20 ;
第二條語句:查詢符合條件的詳細數據,將第一條sql的結果使用in操做拼接到第二條的sql

SELECT DISTINCT g.*, cp.name AS cp_name,c.name AS category_name,t.name AS type_name FROM gm_game g
 LEFT JOIN gm_cp cp ON cp.id = g.cp_id AND cp.deleted = 0
LEFT JOIN gm_category c ON c.id = g.category_id AND c.deleted = 0
LEFT JOIN gm_type t ON t.id = g.type_id AND t.deleted = 0
WHERE g.deleted = 0 and g.id in(…………………) ORDER BY g.modify_time DESC ;
【實測效果】

在SATA機器上測試,優化前大約須要50s,優化後第一條0.3s,第二條0.1s,優化後執行速度是原來的100倍以上,IO從100%降到不到1%

在SSD機器上測試,優化前大約須要7s,優化後第一條0.3s,第二條0.1s,優化後執行速度是原來的10倍以上,IO從100%降到不到1%

能夠看出,優化前磁盤io是性能瓶頸,SSD的速度要比SATA明顯要快,優化後磁盤再也不是瓶頸,SSD和SATA性能沒有差異。

【理論分析】

MySQL在執行SQL查詢時可能會用到臨時表,通常狀況下,用到臨時表就意味着性能較低。

臨時表存儲

MySQL臨時表分爲「內存臨時表」和「磁盤臨時表」,其中內存臨時表使用MySQL的MEMORY存儲引擎,磁盤臨時表使用MySQL的MyISAM存儲引擎;

通常狀況下,MySQL會先建立內存臨時表,但內存臨時表超過配置指定的值後,MySQL會將內存臨時表導出到磁盤臨時表;

Linux平臺上缺省是/tmp目錄,/tmp目錄小的系統要注意啦。

使用臨時表的場景

1)ORDER BY子句和GROUP BY子句不一樣, 例如:ORDERY BY price GROUP BY name;
2)在JOIN查詢中,ORDER BY或者GROUP BY使用了不是第一個表的列 例如:SELECT * from TableA, TableB ORDER BY TableA.price GROUP by TableB.name
3)ORDER BY中使用了DISTINCT關鍵字 ORDERY BY DISTINCT(price)
4)SELECT語句中指定了SQL_SMALL_RESULT關鍵字 SQL_SMALL_RESULT的意思就是告訴MySQL,結果會很小,請直接使用內存臨時表,不須要使用索引排序 SQL_SMALL_RESULT必須和GROUP BY、DISTINCT或DISTINCTROW一塊兒使用 通常狀況下,咱們沒有必要使用這個選項,讓MySQL服務器選擇便可。

直接使用磁盤臨時表的場景

1)表包含TEXT或者BLOB列;
2)GROUP BY 或者 DISTINCT 子句中包含長度大於512字節的列;
3)使用UNION或者UNION ALL時,SELECT子句中包含大於512字節的列;
臨時表相關配置

tmp_table_size:指定系統建立的內存臨時表最大大小; http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_tmp_table_size

max_heap_table_size: 指定用戶建立的內存表的最大大小; http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_max_heap_table_size

注意:最終的系統建立的內存臨時表大小是取上述兩個配置值的最小值。

表的設計原則

使用臨時表通常都意味着性能比較低,特別是使用磁盤臨時表,性能更慢,所以咱們在實際應用中應該儘可能避免臨時表的使用。 常見的避免臨時表的方法有:

1)建立索引:在ORDER BY或者GROUP BY的列上建立索引;
2)分拆很長的列:通常狀況下,TEXT、BLOB,大於512字節的字符串,基本上都是爲了顯示信息,而不會用於查詢條件, 所以表設計的時候,應該將這些列獨立到另一張表。

SQL優化

若是表的設計已經肯定,修改比較困難,那麼也能夠經過優化SQL語句來減小臨時表的大小,以提高SQL執行效率。

常見的優化SQL語句方法以下:

1)拆分SQL語句

臨時表主要是用於排序和分組,不少業務都是要求排序後再取出詳細的分頁數據,這種狀況下能夠將排序和取出詳細數據拆分紅不一樣的SQL,以下降排序或分組時臨時表的大小,提高排序和分組的效率,咱們的案例就是採用這種方法。

2)優化業務,去掉排序分組等操做

有時候業務其實並不須要排序或分組,僅僅是爲了好看或者閱讀方便而進行了排序,例如數據導出、數據查詢等操做,這種狀況下去掉排序和分組對業務也沒有多大影響。

以上是雲棲社區小編爲您精心準備的的內容,在雲棲社區的博客、問答、公衆號、人物、課程等欄目也有的相關內容,歡迎繼續使用右上角搜索按鈕進行搜索mysql , 日誌 , 數據 , 優化 , 排序 磁盤 mysql io佔用太高、mysql 佔用io太高排查、redis io 佔用太高、磁盤io佔用太高、mysql佔用cpu太高,以便於您獲取更多的相關知識。

轉自

MySQL佔用IO太高解決方案 - 阿里雲

https://yq.aliyun.com/ziliao/22643

相關文章
相關標籤/搜索