Mysql佔用CPU太高的時候,該從哪些方面下手進行優化?
佔用CPU太高,能夠作以下考慮:
1)通常來說,排除高併發的因素,仍是要找到致使你CPU太高的哪幾條在執行的SQL,show processlist語句,查找負荷最重的SQL語句,優化該SQL,好比適當創建某字段的索引;
2)打開慢查詢日誌,將那些執行時間過長且佔用資源過多的SQL拿來進行explain分析,致使CPU太高,多數是GroupBy、OrderBy排序問題所致使,而後慢慢進行優化改進。好比優化insert語句、優化group by語句、優化order by語句、優化join語句等等;
3)考慮定時優化文件及索引;
4)按期分析表,使用optimize table;
5)優化數據庫對象;
6)考慮是否是鎖問題;
7)調整一些MySQL Server參數,好比key_buffer_size、table_cache、innodb_buffer_pool_size、innodb_log_file_size等等;
8)若是數據量過大,能夠考慮使用MySQL集羣或者搭建高可用環境。
9)可能因爲內存latch(泄露)致使數據庫CPU高
10)在多用戶高併發的狀況下,任何系統都會hold不住的,因此,使用緩存是必須的,使用memcached或者redis緩存均可以;
11)看看tmp_table_size大小是否偏小,若是容許,適當的增大一點;
12)若是max_heap_table_size配置的太小,增大一點;
13)mysql的sql語句睡眠鏈接超時時間設置問題(wait_timeout)
14)使用show processlist查看mysql鏈接數,看看是否超過了mysql設置的鏈接數(http://www.cnblogs.com/kevingrace/p/6226324.html)
下面分享一例遇到過的案例:
網站在高峯時段訪問,點擊頁面有點卡。登錄服務器,發現機器負載有點高,而且mysql佔用了很高的CPU資源,以下:html
MySQL負載居高不下,若是打開了慢查詢日誌功能,最好的辦法就是針對慢查詢日誌裏執行慢的sql語句進行優化,若是sql語句用了大量的group by等語句,union聯合查詢等確定會將mysql的佔用率提升。因此就須要優化sql語句
除了優化sql語句外,也能夠作一些配置上的優化。在mysql中運行show proceslist;出現下面回顯結果:
1.查詢有大量的Copying to tmp table on disk狀態
明顯是因爲臨時表過大致使mysql將臨時表寫入硬盤影響了總體性能。
Mysql中tmp_table_size的默認值僅爲16MB,在當前的狀況下顯然是不夠用的。
mysql> show variables like "%tmp%";
+-------------------+----------+
| Variable_name | Value |
+-------------------+----------+
| max_tmp_tables | 32 |
| slave_load_tmpdir | /tmp |
| tmp_table_size | 16777216 |
| tmpdir | /tmp |
+-------------------+----------+
4 rows in set (0.00 sec)
解決辦法:調整臨時表大小
1)進mysql終端命令修改,加上global,下次進mysql就會生效
mysql> set global tmp_table_size=33554432;
Query OK, 0 rows affected (0.00 sec)
再次登錄mysql
mysql> show variables like "%tmp%";
+-------------------+----------+
| Variable_name | Value |
+-------------------+----------+
| max_tmp_tables | 32 |
| slave_load_tmpdir | /tmp |
| tmp_table_size | 33554432 |
| tmpdir | /tmp |
+-------------------+----------+
4 rows in set (0.01 sec)
2)my.cnf配置文件修改
[root@www ~]# vim my.cnf
.....
tmp_table_size = 32M
重啓mysql
[root@www ~]# /etc/init.d/mysqld restart
2.show processlist;命令的輸出結果顯示了有哪些線程在運行,能夠幫助識別出有問題的查詢語句。好比下面結果:
Id User Host db Command Time State Info
207 root 192.168.1.25:51718 mytest Sleep 5 NULL
先簡單說一下各列的含義和用途,java
第一列,id,一個標識,你要kill一個語句的時候頗有用。mysql
user列,顯示單前用戶,若是不是root,這個命令就只顯示你權限範圍內的sql語句。linux
host列,顯示這個語句是從哪一個ip的哪一個端口上發出的。呵呵,能夠用來追蹤出問題語句的用戶。redis
db列,顯示這個進程目前鏈接的是哪一個數據庫 。sql
command列,顯示當前鏈接的執行的命令,通常就是休眠(sleep),查詢(query),鏈接(connect)。time列,此這個狀態持續的時間,單位是秒。數據庫
state列,顯示使用當前鏈接的sql語句的狀態,很重要的列,後續會有全部的狀態的描述,請注意,state只是語句執行中的某一個狀態,一個sql語句,已查詢爲例,可能須要通過copying to tmp table,Sorting result,Sending data等狀態才能夠完成,vim
info列,顯示這個sql語句,由於長度有限,因此長的sql語句就顯示不全,可是一個判斷問題語句的重要依據。
常見問題:
通常是睡眠鏈接過多,嚴重消耗mysql服務器資源(主要是cpu, 內存),並可能致使mysql崩潰。
解決辦法 :
在mysql的配置my.cnf文件中,有一項wait_timeout參數設置.便可設置睡眠鏈接超時秒數,若是某個鏈接超時,會被mysql天然終止。
wait_timeout過大有弊端,其體現就是MySQL裏大量的SLEEP進程沒法及時釋放,拖累系統性能,不過也不能把這個指設置的太小,不然你可能會遭遇到「MySQL has gone away」之類的問題。
一般來講,把wait_timeout設置爲10小時是個不錯的選擇,但某些狀況下可能也會出問題,好比說有一個CRON腳本,其中兩次SQL查詢的間隔時間大於10秒的話,那麼這個設置就有問題了(固然,這也不是不能解決的問題,你能夠在程序裏時不時mysql_ping一下,以便服務器知道你還活着,從新計算wait_timeout時間):
MySQL服務器默認的「wait_timeout」是28800秒即8小時,意味着若是一個鏈接的空閒時間超過8個小時,MySQL將自動斷開該鏈接。
然而鏈接池卻認爲該鏈接仍是有效的(由於並未校驗鏈接的有效性),當應用申請使用該鏈接時,就會致使下面的報錯:
The last packet successfully received from the server was 596,688 milliseconds ago.
mysql> show variables like 'wait_timeout';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout | 28800 |
+---------------+-------+
1 row in set (0.00 sec)
28800seconds,也就是8小時。
若是在wait_timeout秒期間內,數據庫鏈接(java.sql.Connection)一直處於等待狀態,mysql就將該鏈接關閉。這時,你的Java應用的鏈接池仍然合法地持有該鏈接的引用。當用該鏈接來進行數據庫操做時,就碰到上述錯誤。
能夠將mysql全局變量wait_timeout的缺省值改大。
查看mysql手冊,發現對wait_timeout的最大值分別是24天/365天(windows/linux)。
好比將其改爲30天
mysql> set global wait_timeout=124800;
Query OK, 0 rows affected (0.00 sec)windows