Mysql占用CPU過高的時候,該從哪些方面下手進(jìn)行優(yōu)化?
占用CPU過高,可以做如下考慮:
1)一般來講,排除高并發(fā)的因素,還是要找到導(dǎo)致你CPU過高的哪幾條在執(zhí)行的SQL,show processlist語句,查找負(fù)荷最重的SQL語句,優(yōu)化該SQL,比如適當(dāng)建立某字段的索引;
2)打開慢查詢?nèi)罩?,將那些?zhí)行時間過長且占用資源過多的SQL拿來進(jìn)行explain分析,導(dǎo)致CPU過高,多數(shù)是GroupBy、OrderBy排序問題所導(dǎo)致,然后慢慢進(jìn)行優(yōu)化改進(jìn)。比如優(yōu)化insert語句、優(yōu)化group by語句、優(yōu)化order by語句、優(yōu)化join語句等等;
3)考慮定時優(yōu)化文件及索引;
4)定期分析表,使用optimize table;
5)優(yōu)化數(shù)據(jù)庫對象;
6)考慮是否是鎖問題;
7)調(diào)整一些MySQL Server參數(shù),比如key_buffer_size、table_cache、innodb_buffer_pool_size、innodb_log_file_size等等;
8)如果數(shù)據(jù)量過大,可以考慮使用MySQL集群或者搭建高可用環(huán)境。
9)可能由于內(nèi)存latch(泄露)導(dǎo)致數(shù)據(jù)庫CPU高
10)在多用戶高并發(fā)的情況下,任何系統(tǒng)都會hold不住的,所以,使用緩存是必須的,使用memcached或者redis緩存都可以;
11)看看tmp_table_size大小是否偏小,如果允許,適當(dāng)?shù)脑龃笠稽c;
12)如果max_heap_table_size配置的過小,增大一點;
13)mysql的sql語句睡眠連接超時時間設(shè)置問題(wait_timeout)
14)使用show processlist查看mysql連接數(shù),看看是否超過了mysql設(shè)置的連接數(shù)
下面分享一例遇到過的案例:
網(wǎng)站在高峰時段訪問,點擊頁面有點卡。登陸服務(wù)器,發(fā)現(xiàn)機器負(fù)載有點高,并且mysql占用了很高的CPU資源,如下圖:
MySQL負(fù)載居高不下,如果打開了慢查詢?nèi)罩竟δ埽詈玫霓k法就是針對慢查詢?nèi)罩纠飯?zhí)行慢的sql語句進(jìn)行優(yōu)化,如果sql語句用了大量的group by等語句,union聯(lián)合查詢等肯定會將mysql的占用率提高。所以就需要優(yōu)化sql語句
除了優(yōu)化sql語句外,也可以做一些配置上的優(yōu)化。在mysql中運行show proceslist;出現(xiàn)下面回顯結(jié)果:
1.查詢有大量的Copying to tmp table on disk狀態(tài)
明顯是由于臨時表過大導(dǎo)致mysql將臨時表寫入硬盤影響了整體性能。
Mysql中tmp_table_size的默認(rèn)值僅為16MB,在當(dāng)前的情況下顯然是不夠用的。
mysql> show variables like "%tmp%"; +-------------------+----------+ | Variable_name | Value | +-------------------+----------+ | max_tmp_tables | 32 | | slave_load_tmp dir | /tmp | | tmp_table_size | 16777216 | | tmpdir | /tmp | +-------------------+----------+ 4 rows in set (0.00 sec)
解決辦法:調(diào)整臨時表大小
1)進(jìn)mysql終端命令修改,加上global,下次進(jìn)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;命令的輸出結(jié)果顯示了有哪些線程在運行,可以幫助識別出有問題的查詢語句。比如下面結(jié)果:
Id User Host db Command Time State Info 207 root 192.168.1.25:51718 mytest Sleep 5 NULL
先簡單說一下各列的含義和用途,第一列,id,不用說了吧,一個標(biāo)識,你要kill一個語句的時候很有用。user列,顯示單前用戶,如果不是root,這個命令就只顯示你權(quán)限范圍內(nèi)的sql語句。host列,顯示這個語句是從哪個ip的哪個端口上發(fā)出的。呵呵,可以用來追蹤出問題語句的用戶。db列,顯示這個進(jìn)程目前連接的是哪個數(shù)據(jù)庫 。command列,顯示當(dāng)前連接的執(zhí)行的命令,一般就是休眠(sleep),查詢(query),連接(connect)。time列,此這個狀態(tài)持續(xù)的時間,單位是秒。state列,顯示使用當(dāng)前連接的sql語句的狀態(tài),很重要的列,后續(xù)會有所有的狀態(tài)的描述,請注意,state只是語句執(zhí)行中的某一個狀態(tài),一個sql語句,已查詢?yōu)槔赡苄枰?jīng)過copying to tmp table,Sorting result,Sending data等狀態(tài)才可以完成,info列,顯示這個sql語句,因為長度有限,所以長的sql語句就顯示不全,但是一個判斷問題語句的重要依據(jù)。
常見問題:
一般是睡眠連接過多,嚴(yán)重消耗mysql服務(wù)器資源(主要是cpu, 內(nèi)存),并可能導(dǎo)致mysql崩潰。
解決辦法 :
在mysql的配置my.cnf文件中,有一項wait_timeout參數(shù)設(shè)置.即可設(shè)置睡眠連接超時秒數(shù),如果某個連接超時,會被mysql自然終止。
wait_timeout過大有弊端,其體現(xiàn)就是MySQL里大量的SLEEP進(jìn)程無法及時釋放,拖累系統(tǒng)性能,不過也不能把這個指設(shè)置的過小,否則你可能會遭遇到“MySQL has gone away”之類的問題。
通常來說,把wait_timeout設(shè)置為10小時是個不錯的選擇,但某些情況下可能也會出問題,比如說有一個CRON腳本,其中兩次SQL查詢的間隔時間大于10秒的話,那么這個設(shè)置就有問題了(當(dāng)然,這也不是不能解決的問題,你可以在程序里時不時mysql_ping一下,以便服務(wù)器知道你還活著,重新計算wait_timeout時間):
MySQL服務(wù)器默認(rèn)的“wait_timeout”是28800秒即8小時,意味著如果一個連接的空閑時間超過8個小時,MySQL將自動斷開該連接。
然而連接池卻認(rèn)為該連接還是有效的(因為并未校驗連接的有效性),當(dāng)應(yīng)用申請使用該連接時,就會導(dǎo)致下面的報錯:
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秒期間內(nèi),數(shù)據(jù)庫連接(java.sql.Connection)一直處于等待狀態(tài),mysql就將該連接關(guān)閉。這時,你的Java應(yīng)用的連接池仍然合法地持有該連接的引用。當(dāng)用該連接來進(jìn)行數(shù)據(jù)庫操作時,就碰到上述錯誤。
可以將mysql全局變量wait_timeout的缺省值改大。
查看mysql手冊,發(fā)現(xiàn)對wait_timeout的最大值分別是24天/365天(windows/linux)。
比如將其改成30天
mysql> set global wait_timeout=124800; Query OK, 0 rows affected (0.00 sec)
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com