设为首页 收藏本站
查看: 623|回复: 0

[经验分享] php垃圾代码优化那档子事

[复制链接]

尚未签到

发表于 2015-8-24 14:33:06 | 显示全部楼层 |阅读模式
  公司有几个网站搭在美国的虚拟主机上,服务器上的mysql服务差不多每一天都会突然不知什么时候挂掉,然后过一会又恢复了,怀疑是超出cpu的使用限制而被自动结束了,但是实际上该服务器上的流量很小。于是早先的时候联系了服务器提供商的印度阿三客服,想看看是不是其他用户搞多了害的大家一起死,阿三们查找了之后,信誓旦旦的拍着长毛的胸部保证不是他们的问题,事情没有解决。悬着不是个事,只好自己查了,好在可以访问到information_schema库,看了看,没话了,user_statistics里面的数据显示我们的一个mysql用户在busy_time,cpu_time等指标上都高到不行,自己的事,好在阿三没有发现。于是赶紧查程序,之前的这个网站程序不是由我做的,但是知道里面问题很多,架构到实现都有问题,但是页面不是一般的多,代码夹杂着html,全看过去还不死,(这种时候就尤为的觉着mvc多美妙),平时能凑合着运行就可以了,反正没有什么访问量。
  既然是mysql的负担重,那就先找这个,本地上搞一个网站的镜像运行下,在my.ini里修改添加
  




[mysqld]
log="d:/temp/mysql.log"
log_slow_queries="d:/temp/mysql_slow.log"
long_query_time=1

  


$sql1="select pz_area.aid,pz_area.ename,tb1.cc from pz_area right join (SELECT aid,count(*) as cc FROM pz_content WHERE uid=$uid group by aid) as tb1 on pz_area.aid=tb1.aid";
$rs1=$db->query($sql1);
if(is_array($rs1)){
  foreach($rs1 as $r1){
输出...
   echo $r1->ename;
  }
}

这个目录是要已经存在的。重启mysql服务,就可以记录了。
  
  查看sql记录后大吃一惊,查询的数量惊人,随便一个页面,sql查询都在几十条,多的有上千条!
  以论坛来说吧,一个页面的数据库查询次数也就是10次一下,用了缓存的还可以再低。这样算的话,就相当于原来几十倍的负担,能不挂?




             14 Query       SELECT * FROM pz_content WHERE uid=19 and sec_id=10 and aid=688 and pic_url<>''
             14 Query       select * from pz_area where aid=688
             14 Query       SELECT * FROM pz_content WHERE uid=19 and sec_id=10 and aid=689 and pic_url<>''
             14 Query       select * from pz_area where aid=689
             14 Query       SELECT * FROM pz_content WHERE uid=19 and sec_id=10 and aid=690 and pic_url<>''
             14 Query       select * from pz_area where aid=690
             14 Query       SELECT * FROM pz_content WHERE uid=19 and sec_id=10 and aid=691 and pic_url<>''
             14 Query       select * from pz_area where aid=691
             14 Query       SELECT * FROM pz_content WHERE uid=19 and sec_id=10 and aid=692 and pic_url<>''
             14 Query       select * from pz_area where aid=692
             14 Query       SELECT * FROM pz_content WHERE uid=19 and sec_id=10 and aid=693 and pic_url<>''
             14 Query       select * from pz_area where aid=693
             14 Query       SELECT * FROM pz_content WHERE uid=19 and sec_id=10 and aid=694 and pic_url<>''
             14 Query       select * from pz_area where aid=694
  谁人也不能那边有毅力写下上百条的查询啊,所以肯定是循环查询。sql语句也表明这一点。知道原因了就好改了,找到相关页面,改掉循环查询,例如,有一个页面,要显示所有地区分类和该分类下的文章数,先不考虑数据库的结构优化,就程序而言,原来的大概是这样子的
  



$sql1="SELECT aid,count(*) as cc FROM pz_content WHERE uid=$uid group by aid";
$rs1=$db->query($sql1);
if(is_array($rs1)){
foreach($rs1 as $r1){
输出...
echo id2name($r1->aid);
}
}
............
function  id2name($aid)
{
$sql="select ename from pz_area_a where aid_a=".$id;
$result=mysql_query($sql);
$row=mysql_fetch_object($result);
return $row->ename;
}

  
先不管代码的容错,看实现就知道,他先读取了该用户的相关文章并按地区ID进行了分组和统计个数,然后再每个地区每个地区地输出地区名字,所以,如果有1w个地区,这里就要查询1w次。放上一个计时的代码,看了下,大概耗用内存6M,执行时间16秒,累计查询1001次
  
  其实,这里是只要用一句sql就可以搞定的事情,并不需要循环。
  
  问题就可以解决了。重新运行下,内存耗用差不多,查询1次,CPU执行时间只有647毫秒,和原来的差了26倍!再看一下,发现这个pz_content的表,记录还算比较多的,有经常要按地区查询划分之类的,但是原来什么索引也没有。顺道在aid上加上一个索引,执行时间缩短到432毫秒。
  
  其实,这样的改动会带来性能上的巨大提升原因也是很明了的。
  从执行机制上,对于每一次的query,libmysql都要将其做个封包,并将数据发送到mysql服务器上的3306(默认)的端口上,这个过程中,数据的封包,网络的传输、响应,都需要时间,请求数量越多,这样的重复性操作所要耗用的时间也就越多。
  再者,mysql对于每次传入sql语句,都会调用mysql optimizer,其将从query parser传递过来的query进行分解拆析,分析出最优的数据检索方式,也就是sql语句的拆解优化。这过程中,首先,解析器会判断出sql的种类是select啊还是其他的,然后会对整个query做个处理,先搞掉一部分的常量表达式运算,直接整成常量值,再做一个简化,去掉些无用的过滤条件,然后分析下query中可能存在的hint信息。然后根据hint信息来决定是否读取相关对象的统计信息,再根据query整成计算分析,再得出最后的执行计划。虽然mysql的sql优化不及Oracle强悍,但是实际上也要经过很多复杂的运算分析,才能得出最后的执行计划,所以,多次的sql查询,也将在这方面增加不必要的性能开销。
  大家都说的,存储过程性能好。为什么好?就好在这里了。在没使用存储过程的情况下,在不会造成过分复杂的查询的前提下,减少sql的查询次数,是提升性能的途径之一。至于说能好多少,那要看具体的情况而定了。
  
  这个页面的事情算了了,先到这里,下次继续。
  


(默认)

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-103576-1-1.html 上篇帖子: 7个鲜为人知却超实用的PHP函数 下篇帖子: php开发2(环境配置2)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表