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)html
下面分享一例遇到过的案例:
网站在高峰时段访问,点击页面有点卡。登录服务器,发现机器负载有点高,而且mysql占用了很高的CPU资源,以下图:java
MySQL负载居高不下,若是打开了慢查询日志功能,最好的办法就是针对慢查询日志里执行慢的sql语句进行优化,若是sql语句用了大量的group by等语句,union联合查询等确定会将mysql的占用率提升。因此就须要优化sql语句mysql
除了优化sql语句外,也能够作一些配置上的优化。在mysql中运行show proceslist;出现下面回显结果:
1.查询有大量的Copying to tmp table on disk状态
明显是因为临时表过大致使mysql将临时表写入硬盘影响了总体性能。linux
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)redis
解决办法:调整临时表大小
1)进mysql终端命令修改,加上global,下次进mysql就会生效
mysql> set global tmp_table_size=33554432;
Query OK, 0 rows affected (0.00 sec)sql
再次登录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 = 32Mvim
重启mysql
[root@www ~]# /etc/init.d/mysqld restartwindows
2.show processlist;命令的输出结果显示了有哪些线程在运行,能够帮助识别出有问题的查询语句。好比下面结果:
Id User Host db Command Time State Info
207 root 192.168.1.25:51718 mytest Sleep 5 NULL
先简单说一下各列的含义和用途,第一列,id,不用说了吧,一个标识,你要kill一个语句的时候颇有用。user列,显示单前用户,若是不是root,这个命令就只显示你权限范围内的sql语句。host列,显示这个语句是从哪一个ip的哪一个端口上发出的。呵呵,能够用来追踪出问题语句的用户。db列,显示这个进程目前链接的是哪一个数据库 。command列,显示当前链接的执行的命令,通常就是休眠(sleep),查询(query),链接(connect)。time列,此这个状态持续的时间,单位是秒。state列,显示使用当前链接的sql语句的状态,很重要的列,后续会有全部的状态的描述,请注意,state只是语句执行中的某一个状态,一个sql语句,已查询为例,可能须要通过copying to tmp table,Sorting result,Sending data等状态才能够完成,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)