如何处理PHP和MYSQL的并发以及优化

2013-10-17 来源: coolid 发布在  http://www.cnblogs.com/coolid/p/3374187.html

sql优化,数据缓存和页面静态化
首先各种优化程序逻辑优化数据库优化硬件横向扩展
数据hash、服务器提升性能、表hash、出钱找oraclec出解决方案
页面静态化:
Php页面静态化有两种,第一,php模板,比如:smarty。第二,url伪静态,通过urlrewrite实现这种做法可以提高网站的排名和收索
像一些管理性质的网站,比如:新闻发布系统、CMS等,使用php模板静态化。一般的网站伪静态就可以了
数据缓存:
php程序常规的获取数据的流程是:
1.用户向php程序发送请求
2.php请求从数据库中取出数据
3.发送给用户
但是当网站的访问量非常大的时候数据库往往成为制约系统性能的瓶颈,为了减轻大规模请求对数据库造成的压力,简单的方法可以采用数据缓存来减轻数据库的压力,下面就简单的介绍一下常规的数据缓存方法:
具体的步骤:
1.用户请求
2.判断缓存是否存在或者是否过期
3.如果缓存不存在或者缓存已经过期,从数据库中读出数据;如果没有过期,读取缓存
4.发送给用户
文件方式缓存数据示例代码:
                                   
1
           
2
           
3
           
4
           
5
           
6
           
7
           
8
           
9
           
10
           
11
           
12
           
13
           
14
           
15
           
16
           
17
           
18
           
19
           
20
                                   
//数据库连接省略
           
           
$cache_dir='cache';//缓存文件夹
           
$cache_time='60';//缓存时间
           
$sql='select*fromtest';
           
$cache_file=$cache_dir.'/'.md5($sql);//以sql语句的md5值作为缓存文件名(当然也可以用其他方式)
           
           
//如果缓存存在并且缓存未过期
           
if(file_exists($cache_file)&&time()-filemtime($cache_file)<$cache_time){
           
$data=unserialize(file_get_contents($cache_file));//读取缓存后反序列化
           
}else{
           
//读取数据库
           
$query=mysql_query($sql);
           
//省略...
           
$data="数据库中读取...";
           
//把读取的数据序列化后写入缓存
           
file_put_contents($cache_file,serialize($data));
           
}
           
//呵呵,这里就是想要的数据
           
print_r($data);
                       
Memcache缓存数据示例:
                                   
1
           
2
           
3
           
4
           
5
           
6
           
7
           
8
           
9
           
10
           
11
           
12
           
13
           
14
           
15
           
16
           
17
           
18
                                   
//先要安装memcache服务端和memcachephp扩展
           
$memcache=newMemcache;
           
$memcache->connect('localhost',11211)ordie("Couldnotconnect");
           
$cache_time='60';//缓存时间
           
$sql='select*fromtest';
           
$key=md5($sql);
           
           
if(!$memcache->get($key)){//如果缓存不存在
           
//读取数据库
           
$query=mysql_query($sql);
           
//省略...
           
$data="数据库中读取...";
           
//把读取的数据写入缓存
           
$memcache->set($key,$data,0,$cache_time);
           
}else{//缓存存在
           
$data=$memcache->get($key);//读取缓存
           
}
           
print_r($data);
                       
sql优化:
根据情况选择最优的引擎是innodb还是myisam,比如mysql有很多第三方开源优化方案Facebook在mysql的第三方插件使用上有很多做法。Pdo
innodb还是myisam
常用于读取的数据表,sql引擎选择myisam
常用于插入、修改、删除等操作的数据表,sql引擎选择innodb
1.查询的模糊匹配
尽量避免在一个复杂查询里面使用LIKE'%parm1%'——红色标识位置的百分号会导致相关列的索引无法使用,最好不要用.
解决办法:
其实只需要对该脚本略做改进,查询速度便会提高近百倍。改进方法如下:
a、修改前台程序——把查询条件的供应商名称一栏由原来的文本输入改为下拉列表,用户模糊输入供应商名称时,直接在前台就帮忙定位到具体的供应商,这样在调用后台程序时,这列就可以直接用等于来关联了。
b、直接修改后台——根据输入条件,先查出符合条件的供应商,并把相关记录保存在一个临时表里头,然后再用临时表去做复杂关联
2.索引问题
在做性能跟踪分析过程中,经常发现有不少后台程序的性能问题是因为缺少合适索引造成的,有些表甚至一个索引都没有。这种情况往往都是因为在设计表时,没去定义索引,而开发初期,由于表记录很少,索引创建与否,可能对性能没啥影响,开发人员因此也未多加重视。然一旦程序发布到生产环境,随着时间的推移,表记录越来越多
这时缺少索引,对性能的影响便会越来越大了。
这个问题需要数据库设计人员和开发人员共同关注
法则:不要在建立的索引的数据列上进行下列操作:
*避免对索引字段进行计算操作
*避免在索引字段上使用not,<>,!=
*避免在索引列上使用ISNULL和ISNOTNULL
*避免在索引列上出现数据类型转换
*避免在索引字段上使用函数
*避免建立索引的列中使用空值。
3.复杂操作
部分UPDATE、SELECT语句写得很复杂(经常嵌套多级子查询)——可以考虑适当拆成几步,先生成一些临时数据表,再进行关联操作
4.update
同一个表的修改在一个过程里出现好几十次,如:
                                   
updatetable1
           setcol1=...
           wherecol2=...;
           updatetable1
           setcol1=...
           wherecol2=...
           ......
                       
象这类脚本其实可以很简单就整合在一个UPDATE语句来完成(前些时候在协助xxx项目做性能问题分析时就发现存在这种情况)
5.在可以使用UNIONALL的语句里,使用了UNION
UNION因为会将各查询子集的记录做比较,故比起UNIONALL,通常速度都会慢上许多。一般来说,如果使用UNIONALL能满足要求的话,务必使用UNIONALL。还有一种情况大家可能会忽略掉,就是虽然要求几个子集的并集需要过滤掉重复记录,但由于脚本的特殊性,不可能存在重复记录,这时便应该使用UNIONALL,如xx模块的某个查询程序就曾经存在这种情况,见,由于语句的特殊性,在这个脚本中几个子集的记录绝对不可能重复,故可以改用UNIONALL)
6.在WHERE语句中,尽量避免对索引字段进行计算操作
这个常识相信绝大部分开发人员都应该知道,但仍有不少人这么使用,我想其中一个最主要的原因可能是为了编写写简单而损害了性能,那就不可取了
9月份在对XX系统做性能分析时发现,有大量的后台程序存在类似用法,如:
                                   
......
           wheretrunc(create_date)=trunc(:date1)
                       
虽然已对create_date字段建了索引,但由于加了TRUNC,使得索引无法用上。此处正确的写法应该是
                                   
wherecreate_date>=trunc(:date1)andcreate_date<PRE>
                       
或者是
                                   
wherecreate_datebetweentrunc(:date1)andtrunc(:date1)+1-1/(24*60*60)
                       
注意:因between的范围是个闭区间(greaterthanorequaltolowvalueandlessthanorequaltohighvalue.),
故严格意义上应该再减去一个趋于0的小数,这里暂且设置成减去1秒(1/(24*60*60)),如果不要求这么精确的话,可以略掉这步。
7.对Where语句的法则
7.1避免在WHERE子句中使用in,notin,or或者having。
可以使用exist和notexist代替in和notin。
可以使用表链接代替exist。Having可以用where代替,如果无法代替可以分两步处理。
例子
                                   
SELECT*FROMORDERSWHERECUSTOMER_NAMENOTIN
           (SELECTCUSTOMER_NAMEFROMCUSTOMER)
                       
优化
                                   
           SELECT*FROMORDERSWHERECUSTOMER_NAMEnotexist
           (SELECTCUSTOMER_NAMEFROMCUSTOMER)
                       
7.2不要以字符格式声明数字,要以数字格式声明字符值。(日期同样)否则会使索引无效,产生全表扫描。
例子使用:
                                   
SELECTemp.ename,emp.jobFROMempWHEREemp.empno=7369;
           不要使用:SELECTemp.ename,emp.jobFROMempWHEREemp.empno=&lsquo;7369&rsquo;
                       
8.对Select语句的法则
在应用程序、包和过程中限制使用select*fromtable这种方式。看下面例子
                                   
使用SELECTempno,ename,categoryFROMempWHEREempno='7369&lsquo;
           而不要使用SELECT*FROMempWHEREempno='7369'
                       
9.排序
避免使用耗费资源的操作,带有DISTINCT,UNION,MINUS,INTERSECT,ORDERBY的SQL语句会启动SQL引擎执行,耗费资源的排序(SORT)功能.DISTINCT需要一次排序操作,而其他的至少需要执行两次排序
10.临时表
慎重使用临时表可以极大的提高系统性能
新浪微博对大数据量处理还用到了热点数据处理方法类似于热点数据缓存
淘宝在大型活动时为了保证不宕机会采用降级服务
这些都是我知道的大并发处理方法

相关文章