.net代码优化
一、数据库操作
1、用完马上关闭数据库连接
访问数据库资源需要创建连接、打开连接和关闭连接几个操作。这些过程需要多次与数据库交换信息以通过身份验证,比较耗费服务器资
源。ASP.NET中提供了连接池(Connection Pool)改善打开和关闭数据库对性能的影响。系统将用户的数据库连接放在连接池中,需要时取出,关闭时收回连接,等待下一次的连接请求。
连接池的大小是有限的,如果在连接池达到最大限度后仍要求创建连接,必然大大影响性能。因此,在建立数据库连接后只有在真正需要操作时才打开连接,使用完毕后马上关闭,从而尽量减少数据库连接打开的时间,避免出现超出连接限制的情况。
用(推荐)
using(SqlConnection Conn=new SqlConnection(connstr))
{}//不必显示关闭
或
try{conn.Open();}
catch{}
finally{conn.Close();}
2、尽量使用存储过程,并优化查询语句
存储过程是存储在服务器上的一组预编译的SQL语句,类似于DOS系统中的批处理文件。存储过程具有对数据库立即访问的功能,信息处理极为迅速。使用存储过程可以避免对命令的多次编译,在执行一次后其执行规划就驻留在高速缓存中,以后需要时只需直接调用缓存中的二进制代码即可。在 .NET Framework 提供的所有数据访问方法中,基于 SQL Server 的数据访问是生成高性能、可缩放 Web 应用程序的推荐选择。使用托管 SQL Server 提供程序时,可通过使用编译的存储过程而不是特殊查询获得额外的性能提高。
另外,存储过程在服务器端运行,独立于ASP.NET程序,便于修改,最重要的是它可以减少数据库操作语句在网络中的传输。
优化查询语句
ASP.NET中ADO连接消耗的资源相当大,SQL语句运行的时间越长,占用系统资源的时间也越长。因此,尽量使用优化过的SQL语句以减少执行时间。比如,不在查询语句中包含子查询语句,尽量只返回有用的数据、字段,充分利用索引等。
3、只读数据访问用SqlDataReader,不要使用DataSet
SqlDataReader 类提供了一种读取从 SQL Server 数据库检索的只进数据流的方法。如果当创建 ASP.NET 应用程序时出现允许您使用它的情况,则 SqlDataReader 类提供比 DataSet 类更高的性能。情况之所以这样,是因为 SqlDataReader 使用 SQL Server 的本机网络数据传输格式从数据库连接直接读取数据。另外,SqlDataReader 类实现 IEnumerable 接口,该接口也允许您将数据绑定到服务器控件。DataSet作为一个功能强大的、支持离线的数据库,其对性能的开销也相对较大。
Sqldataread优点:读取数据非常快。如果对返回的数据不需做大量处理的情况下,建议使用SqlDataReader,其性能要比datset好很多。缺点:直到数据读完才可close掉于数据库的连接。
Dataset是把数据读出,缓存在内存中。缺点:对内存的占用较高。如果对返回的数据需做大量的处理用Dataset比较好些可以减少对数据库的连接操作。优点:只需连接一次就可close于数据库的连接。
一般情况下,读取大量数据,对返回数据不做大量处理用SqlDataReader.对返回数据大量处理用datset比较合适.对SqlDataReader和Dataset的选择取决于程序功能的实现。
4、返回多个结果集
无论SqlDataReader还是datset,返回多个结果集,然后用rd.NextResult()或ds.Tables[i]来分别处理数据,减少重复连接数据库的次数。同时尽量用比较高效的SQL代替后续复杂的DataSet二次加工。
5、运用StringBuilder类
String类对象是不可改变的,对于String对象的重新赋值在本质上是重新创建了一个String对象并将新值赋予该对象,其方法ToString对性能的提高并非很显著。
在处理字符串时,最好使用StringBuilder类,其.NET 命名空间是System.Text。该类并非创建新的对象,而是通过Append,Remove,Insert等方法直接对字符串进行操作,通过ToString方法返回操作结果。
其定义及操作语句如下所示:
int num;
System.Text.StringBuilder str = new System.Text.StringBuilder(); //创建字符串
str.Append(num.ToString()); //添加数值num
7、不要用ToUpper(),ToLower()转换字符串进行比较,用String.Compare代替,它可以忽略大小写进行比较.
例:
const string C_VALUE = "COMPARE";
if (String.Compare(sVariable, C_VALUE, true) == 0)
{
Console.Write( "相同");
}
也可以用str == String.Empty或者str.Length == 0判断是否为空。(注意判断输入数据的长度,可防止sql注入式攻击)
将String对象的Length属性与0比较是最快的方法,避免不必要的调用 ToUpper 或 ToLower 方法。
8、类型转化Int32.TryParse()优于Int32.Parse()优于Convert.ToInt32()。
建议.NET1.1下用Int32.Parse();.NET2.0用Int32.TryParse()。
因为:
Convert.ToInt32 会把最终的解析工作代理给 Int32.Parse;
Int32.Parse 会把最终的解析工作代理给Number.ParseInt32;
Int32.TryParse 会把最终的解析工作代理给Number.TryParseInt32。
尽量避免Exception
.NET的Exception是一种特殊的类型,不管用户代码是否处理exception,只要产生,就会在CLR上有开销。所以尽量避免产生Exception,尤其是不要利用Exception控制程序流程,这一点通常在.NET的技术文章里都会提及。一个不正常利用Exception的例子是我曾经在公司代码里看见过类似这样判断输入的内容是否为数字的代码:
try
{
Convert.ToInt32(userInput);
return true;
}
catch (Exception ex)
{
return false;
}
而.NET其实可以这样写:
int.TryParse(userInput);
我相信大部分正常的.NET程序员都不会犯上面这种错误。这样的代码效率低下且不说,还容易炸毁IIS。IIS的应用程序池如果在短时间检测到大量CLR异常就会自爆重启并返回503,中断你的网站服务。
不过关于Exception的另一个争论点在于,是否需要为业务异常设计自己的Exception类型?也就是检查到非正常业务行为,到底返回Error Code还是直接抛出Exception再由上层处理?关于这点,我也没有确定的结论。目前我的实践是,仅对于非法输入抛出参数异常,业务上的错误不抛异常,例如文章被和谐后产生的404,不去设计比如 PostNotFoundException,这一点很关键,因为经常有无聊黑客新手使用自动化工具扫描我的博客是否有漏洞,而这些工具会批量请求例如wp-login.php之类的对于我博客来说不存在的资源,如果我设计成抛出Exception再返回404,那么会造成短时间内CLR上大量的异常,绝对会爆。
浙公网安备 33010602011771号