惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 三生石上(FineUI控件)
雷峰网
雷峰网
爱范儿
爱范儿
P
Proofpoint News Feed
Security Archives - TechRepublic
Security Archives - TechRepublic
Latest news
Latest news
The Hacker News
The Hacker News
Cyberwarzone
Cyberwarzone
博客园 - 【当耐特】
Project Zero
Project Zero
小众软件
小众软件
T
Tailwind CSS Blog
量子位
博客园 - 聂微东
I
Intezer
美团技术团队
S
SegmentFault 最新的问题
T
Tor Project blog
Spread Privacy
Spread Privacy
V
Vulnerabilities – Threatpost
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Jina AI
Jina AI
罗磊的独立博客
B
Blog RSS Feed
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Troy Hunt's Blog
有赞技术团队
有赞技术团队
Google DeepMind News
Google DeepMind News
宝玉的分享
宝玉的分享
C
Cisco Blogs
L
LINUX DO - 热门话题
Last Week in AI
Last Week in AI
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
AI
AI
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Microsoft Azure Blog
Microsoft Azure Blog
L
LINUX DO - 最新话题
Know Your Adversary
Know Your Adversary
GbyAI
GbyAI
Engineering at Meta
Engineering at Meta
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Recent Commits to openclaw:main
Recent Commits to openclaw:main
L
Lohrmann on Cybersecurity
The Register - Security
The Register - Security
L
LangChain Blog
博客园 - 叶小钗
T
Tenable Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC

博客园 - xin478

使用nfs共享session文件导致 session_start异常缓慢问题 linux下抓取网页截图 nginx proxy_pass末尾神奇的/ 在php中使用SMTP通过密抄批量发送邮件续:修正 无聊闲做,从使用PHP数组实现约瑟夫环问题谈性能 在php中使用SMTP通过密抄批量发送邮件 使用VisualStudio开发php mysql常用的hint[转] 配置windows下php+apache+mysql环境 惨啊!mp4固件升级惊魂 用PHP实现POP3邮件的收取 希捷酷鱼12 500G的确有问题,好惨啊 解决IE6下PNG透明问题,支持平铺背景图片 VS.PHP with VS2008 in windows7 windows7蓝屏啦 mysql使用rand随机查询记录效率测试 特殊字符的html编码转化 - xin478 - 博客园 asp.net页面事件执行顺序 在visual studio中随意更改中文字体的方法
php垃圾代码优化那档子事
xin478 · 2010-08-03 · via 博客园 - xin478

公司有几个网站搭在美国的虚拟主机上,服务器上的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的查询次数,是提升性能的途径之一。至于说能好多少,那要看具体的情况而定了。

这个页面的事情算了了,先到这里,下次继续。

(默认)