谈谈对网站性能的优化和一些解决方案
随着用户访问量和网站数量的增加,我们的网站不可避免的会出现性能问题。
一.下面先从大的方面说说解决方法: http://www.cnblogs.com/aaa6818162/archive/2009/03/19/1416395.html
一.下面先从大的方面说说解决方法: http://www.cnblogs.com/aaa6818162/archive/2009/03/19/1416395.html
1:html静态化
2:图片服务器分离
3:数据库集群
4:缓存
5:负载均衡
二.从编程人员的习惯和设计上说
1.数据库(最重要)
(1) 重新调整或重新设计 DB schema、索引 (index)
如:避免把常用的字段、很少用的字段,都塞在同一个表中,而影响数据扫描的速度。
应该将很少用的字段,另切割出来成为另一个表。
(参考: http://www.cnblogs.com/WizardWu/archive/2008/10/27/1320055.html)
(2)改写 SQL 语句
如:避免在 WHERE 子句中对字段使用函数
尽可能在数据来源层,就先过滤数据
返回有用的数据结果,不要选择不使用的数据字段
在不影响开发效率的情况小尽可能的使用存储过程
2.程序代码方面
(1)数据访问层
1.1 能用 DataReader 就不要用 DataSet / DataTable,前者读取速度快又不耗内存;
后者虽较有弹性,但速度较慢又会每个使用者消耗许多内存。
1.2 尽量使用存储过程返回数据
1.3 尽量一次返回多个记录集,而不是每个记录集分别打开一次数据库连接进行查询。
1.4 尽量晚的打开数据库连接,尽量早地关闭数据库连接,(尽量使用using语句关闭数据库连接,)
1.5 使用连接池提高网站性能,不要变动数据库连接字符串,应该尽量早的关闭连接,
(2)缓存
对那些经常使用的数据和需要大量的时间来创建的数据可以存储在内存中,后来的请求直接使用,不需要在从新生成,
使用方法很简单:<%@OutputCache VaryByParams="none" Duration="120"%>
使用缓存的原则:
2.1)在页面中静态的内容和动态的内容分割开来。
可以把动态内容单独出来,做成用户控件
2.2)缓存合理的数据
并不是所有的数据内容都进行缓存就能提高性能的,由于服务器的资源是有限的,缓存不适当的数据反而会降低性能,应当缓存的应该是应用程序级的数据,多个用户共同使用的数据,静态数据,生成数据需要开销很大的数据,DataSet以及自定义的对象等,不要缓存数据库连接对象,不要缓存DataReader.
(3)页面处理
3.1)尽量减少页面文件的大小
3.2)通过Page.IsPostBack减少代码的执行数量。
3.3)禁用Debug="true" 减少页面生成额外的调试信息,
3.4)使用Server.Transfer而不使用Response.Redirect
3.5)尽量避免嵌套服务器控件。
避免使用Page.DataBind和DataBinder.Eval
Page.DataBind执行时会将页面中所有的服务器控件执行一次DataBind方法,如果没有必要就不要使用。
DataBinder.Eval方法是使用反射来获取参数的。尽量少使用,
尽量不要使用:
<ItemTemplate>
<tr>
<td><%#DataBinder.Eval(Container.DataItem,"字段一"))%></td>
<td><%#DataBinder.Eval(Container.DataItem,"字段一"))%></td>
</tr>
</ItemTemplate>
而使用:
<ItemTemplate>
<tr>
<td><%#(DataRowView)Container.DataItem["字段1"]%></td>
<td><%#(DataRowView)Container.DataItem["字段1"]%></td>
</tr>
</ItemTemplate>
3.6)不使用不必要的Server Control
ASP.net中,大量的服务器端控件方便了程序开发,但也可能带来性能的损失,因为用户每操作一次服务器端控件,就产生一次与服务器端的往返过程。因此,非必要,应当少使用Server Control。
(4)代码方面
4.1)在字符串长度未知,并且比较长的情况下使用SringBuilder对象
4.2)不要使用StrVar==""来判断字符串是否为空,这样会产生额外的字符串,请使用StrVar==String.Empty代替,或者使用StrVar.Length==0来判断
4.3)在解析基本数据类型是,使用TryParse方法比Try好
4.4)不要使用如下方法
string[]arr=new string{"fly","flying"}
for(int i=0;i<arr.Length;i++)
{
//TODO
}
这种方法每循环一次就计算一次arr.Length的值。而使用
string[]arr=new string{"fly","flying"}
int length=arr.Length;
for(int i=0;length;i++)
{
//TODO
}
4.5)避免在循环里创建对象
for(int i=0;i<10;i++)
{
SqlConnection cn=new SqlConnection();
//ToDo
}
而使用
SqlConnection cn=new SqlConnection();
for(int i=0;i<10;i++)
{
//ToDo
}
4.6) 尽量减少装箱的次数,如果要在多处进行类型转换,请先定义一个变量
如:
int i=129;
object box;
box=(objiect)i;
//下面多次使用Box;
4.7)不要使用例外控制程序流程,
void UserExists(string UserID)
{
if(dr.Read())
{
throw(new Exception("用户名不存在");
}
}
修改代码如下:
bool UserExists(string UserID)
{
return dr.HasRows;
}
4.8)在循环中不要使用不变的对象或者字段,例如:
for(int i=0;i<Customer.Order.Count;i++)
{
PrintCustomerData(Customer.State,Customer.Zip,Customer.Order[i]);
}
这样的话没错循环都要查找对象的属性值 或者字段。
string state=Customer.State;
string []zip=Customer.Zip;
int count=Customers.Order.Count;
for(int i=0;i<count;i++)
{
PrintCustomerData(state,zip,Customer.Order[i]);
}
4.9)使用for循环代替foreach循环
4.10)数组是所有集合中最快的,如果没有特殊的需要,尽量使用数组代替集合
4.11)了解各个集合的特性,选择合适的类型,
4.12)使用泛型,避免减少使用装箱,拆箱。
4.13)不要依赖代码中的异常
因为异常大大地降低性能,所以您不应该将它们用作控制正常程序流程的方式。如果有可能检测到代码中可能导致异常的状态,请执行这种操作。不要在处理该状态之前捕获异常本身。常见的方案包括:检查 null,分配给将分析为数字值的 String 一个值,或在应用数学运算前检查特定值。下面的示例演示可能导致异常的代码以及测试是否存在某种状态的代码。两者产生相同的结果。
try
{
result = 100 / num;
}
catch (Exception e)
{
result = 0;
}
if (num != 0)
result = 100 / num;
else
result = 0;
(2)使用设计模式