1、现象概述和初步分析<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />mysql
在生产系统中最近常常发现数据库CPU冲高的现象,冲高的时间不定最长状况有达到过2、30分钟的状况,甚至会较严重的影响数据库服务器的运行和稳定。每次出现这种状况的,如下的sql语句出现的几率较大:sql
select count(*) from ( select * from xxx) as new数据库
根据上述现象,咱们初步把测试重点放在了引发该语句的商户查询模块上,针对这一模块进行了屡次压力测试,但不管是10个并发甚至更多,数据库的CPU利用率一直很低,没法重现CPU冲高的状况。缓存
面对这样的测试结果,咱们考虑到:若是该问题与这一语句和模块相关,那么在现实生产环境中,必然有其它因素影响了这一模块的性能。通过进一步的分析,咱们把关注点转向了MySQL的查询缓存方面。服务器
2、针对Mysql缓存的分析并发
在这里咱们首先对MySQL查询缓存进行简单的解释:oracle
从4.0.1开始,MySQL提供了查询缓冲机制。使用查询缓冲,MySQL将SELECT语句和查询结果存放在缓冲区中,从此对于一样的SELECT语句(区分大小写),将直接从缓冲区中读取结果。框架
能够想见,在相对简单的测试环境中,缓存的命中率是很高的,而因为在生产环境存在着对表的更新,因此每每致使查询缓存不能命中,所以当执行这条语句的时候,它所须要的结果再也不缓存中就必须从新进行查询动做。sqlserver
而根据监控的日志,在这些sql语句的出现问题时时也每每伴有对这些表的updata语句。因此以往咱们的测试手段其实是忽视了这个问题,所以没能将问题重现。针对这个问题咱们改变了测试的方法。性能
3、针对Mysql缓存的性能测试
首先在mysql中手动执行sql语句,并在每次执行sql语句以前执行命令:flush tables来清空缓存,这样就可以真实的反映sql语句的性能。select count(*) from (select * from xxx) as new其平均执行的时间为18.22秒,说明这个SQL的确存在性能问题,而其等价写法select count(*) from xxx的平均执行时间仅在0.05秒左右或更低,两者相差居然达到数百倍之多。
(注:咱们的程序中SQL语句采用此种写法,是由于程序框架自动生成的标准SQL语句,为了适应一些特殊状况,因此采用这种统一写法。在大型商业应用的开发过程当中,咱们都是在oracle进行标准下开发,完成后再移植到mysql下面的)
为了验证咱们对于查询缓存影响的推论,咱们将数据库中关于缓存的一项设置为0,即query_cache_size=0,那么这样在进行压力测试的时候每个并发用户的每一次操做都不会从查询缓存中直接返回结果。如下是在1个并发用户的状况下,关闭查询缓存的状况下,执行的状况,从性能上看1个并发用户的平均响应时间是7.454秒,具体以下:
Transaction Summary
Total Passed: 2,988
Total Failed: 0
Total Stopped: 0
Transaction Name
<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />SLAStatus
Minimum
Average
Maximum
Std. Deviation
90 Percent
Pass
Fail
Stop
Service Level Agreement Legend:
Pass
Fail
No Data
在并发测试同时对操做系统进行监控,和咱们所预料到的同样,此次即便在只有1个并发用户的状况下也出现了CPU冲高的状况,同时在这种状况下磁盘的压力很大,每秒写磁盘的峰值甚至可以达到数十M,虽然这是一个查询语句,可是因为使用了中间表所以可能mysql将中间表做为临时表进行了存储,而这些数据量就是在写临时表时候产生的。
4、针对Oracle和SqlServer的性能测试
因为根据以往咱们对oracle和sqlserver的开发经验,这种写法是不存在问题的,为了更全面的分析问题,咱们将存贮在mysql下的表导入到oracle10G中,使用一样的查询进行测试比对,咱们发现两种sql写法的执行效果是没有明显的效率差异,其单个用户的查询时间在百分之几秒级别(大概在0.015-0.05秒之间),在sqlserver2000中,发现两种不一样写法的执行时间都很是的接近而且高效(执行时间均在50毫秒左右)。这个问题在咱们已经测试的三种数据库中,仅在Mysql数据库中存在。
注:这次测试的三种数据库版本分别为:
mysql5.0.48
oracle 10g
sqlserver 2000
5、结论及解决建议
所以,通过上面的分析,咱们基本能够判断该问题的产生是因为在缓存没法命中的状况下,Mysql的查询优化器在执行这种sql语句的时候并无使用最优化或最聪明的执行方式,该SQL语句在MYSQL数据库中的执行效率存在问题。
咱们能够换另一种sql写法,应该可以提升效率至数百倍,有可能消除CPU冲高的现象。
最后通过咱们向mysql厂商求证,的确innodb引擎对select count(*) from (select * from xxx) as new 结构的sql执行是存在性能问题的,而若是采用myisam引擎就不会存在性能问题。