一、数据库操作 1、用完马上关闭数据库连接 访问数据库资源需要创建连接、打开连接和关闭连接几个操作。这些过程需要多次与数据库交换信息以通过身份验证,比较耗费服务器资 源。ASP.NET中提供了连接池(Connection Pool)改善打开和关闭数据库对性能的影响。系统将用户的数据库连接放在连接池中,需要时取出,关闭时收回连接,等待下一次的连接请求。
用(推荐) 或
存储过程是存储在服务器上的一组预编译的SQL语句,类似于DOS系统中的批处理文件。存储过程具有对数据库立即访问的功能,信息处理极为迅 速。使用存储过程可以避免对命令的多次编译,在执行一次后其执行规划就驻留在高速缓存中,以后需要时只需直接调用缓存中的二进制代码即可。在 .NET Framework 提供的所有数据访问方法中,基于 SQL Server 的数据访问是生成高性能、可缩放 Web 应用程序的推荐选择。使用托管 SQL Server 提供程序时,可通过使用编译的存储过程而不是特殊查询获得额外的性能提高。 另外,存储过程在服务器端运行,独立于ASP.NET程序,便于修改,最重要的是它可以减少数据库操作语句在网络中的传输。 优化查询语句 ASP.NET中ADO连接消耗的资源相当大,SQL语句运行的时间越长,占用系统资源的时间也越长。因此,尽量使用优化过的SQL语句以减少执行时间。比如,不在查询语句中包含子查询语句,尽量只返回有用的数据、字段,充分利用索引等。
SqlDataReader 类提供了一种读取从 SQL Server 数据库检索的只进数据流的方法。如果当创建 ASP.NET 应用程序时出现允许您使用它的情况,则 SqlDataReader 类提供比 DataSet 类更高的性能。情况之所以这样,是因为 SqlDataReader 使用 SQL Server 的本机网络数据传输格式从数据库连接直接读取数据。另外,SqlDataReader 类实现 IEnumerable 接口,该接口也允许您将数据绑定到服务器控件。DataSet作为一个功能强大的、支持离线的数据库,其对性能的开销也相对较大。 Sqldataread优点:读取数据非常快。如果对返回的数据不需做大量处理的情况下,建议使用SqlDataReader,其性能要比datset好很多。缺点:直到数据读完才可close掉于数据库的连接。
一般情况下,读取大量数据,对返回数据不做大量处理用SqlDataReader.对返回数据大量处理用datset比较合适.对SqlDataReader和Dataset的选择取决于程序功能的实现。
一般的绑定方法<%# DataBinder.Eval(Container.DataItem, "字段名") %> 用DataBinder.eval 绑定不必关心数据来源(read或dataset)。不必关心数据的类型eval会把这个数据对象转换为一个字符串。在底层绑定做了很多工作,使用了反射性能。正因为使用方便了,但却影响了数据性能。 来看下<%# DataBinder.Eval(Container.DataItem, "字段名") %>。当于dataset绑定时,DataItem其实式一个DataRowView(如果绑定的是一个数据读取器(dataread)它就是一个 IdataRecord。)因此直接转换成DataRowView的话,将会给性能带来很大提升。 <%# ctype(Container.DataItem,DataRowView).Row("字段名") %> 对数据的绑定建议使用<%# ctype(Container.DataItem,DataRowView).Row("字段名") %>。使用时注意两个方面: 以上的是vb.net的写法。在c#中:<%# ((DataRowView)Container.DataItem)["字段名"] %> 5、返回多个结果集 无论SqlDataReader还是datset,返回多个结果集,然后用rd.NextResult()或ds.Tables[i]来分别处理数据,减少重复连接数据库的次数。同时尽量用比较高效的SQL代替后续复杂的DataSet二次加工。 二、页面优化
ASP.net中,大量的服务器端控件方便了程序开发,但也可能带来性能的损失,因为用户每操作一次服务器端控件,就产生一次与服务器端的往返过 程。因此,非必要,应当少使用Server Control。还有许多其他情况,在这些情况中呈现或数据绑定比使用服务器控件更有效,甚至是在使用服务器控件模板时。但是,如果要以编程方式操作服务 器控件的属性、处理服务器控件事件或利用视图状态保存,则使用服务器控件是适当的。 所以,尽量选择html控件。能在客户端实现的功能就在客户端实现(熟练掌握javascript),减少服务器的压力。
默认情况下,ASP.Net对所有的Server Control都启用了ViewState(视图状态)。但ViewState需要在客户端保存一些信息,这会造成性能的消耗。当必须使用Server Control时,可以考虑禁止ViewState。 默认情况下,为所有服务器控件启用视图状态。若要禁用视图状态,请将控件的 EnableViewState 属性设置为 false,如下面的 DataGrid 服务器控件示例所示。 <asp:datagrid EnableViewState="false" runat="server"/> 注意 @ Control 指令中也支持 EnableViewState 属性,该指令允许您控制是否为用户控件启用视图状态。 3、避免到服务器的不必要的往返过程 虽然您很可能希望尽量多地使用 Web 窗体页框架的那些节省时间和代码的功能,但在某些情况下却不宜使用 ASP.NET 服务器控件和回发事件处理。 通常,只有在检索或存储数据时,您才需要启动到服务器的往返过程。多数数据操作可在这些往返过程间的客户端上进行。例如,从 HTML 窗体验证用户输入经常可在数据提交到服务器之前在客户端进行。通常,如果不需要将信息传递到服务器以将其存储在数据库中,那么您不应该编写导致往返过程的 代码。 如果您开发自定义服务器控件,请考虑让它们为支持 ECMAScript 的浏览器呈现客户端代码。通过以这种方式使用服务器控件,您可以显著地减少信息被不必要的发送到 Web 服务器的次数。 使用 Page.IsPostBack 避免对往返过程执行不必要的处理 如果您编写处理服务器控件回发处理的代码,有时可能需要在首次请求页时执行其他代码,而不是当用户发送包含在该页中的 HTML 窗体时执行的代码。根据该页是否是响应服务器控件事件生成的,使用 Page.IsPostBack 属性有条件地执行代码。例如,下面的代码演示如何创建数据库连接和命令,该命令在首次请求该页时将数据绑定到 DataGrid 服务器控件。 由于每次请求时都执行 Page_Load 事件,上述代码检查 IsPostBack 属性是否设置为 false。如果是,则执行代码。如果该属性设置为true,则不执行代码。 注意 如果不运行这种检查,回发页的行为将不更改。Page_Load 事件的代码在执行服务器控件事件之前执行,但只有服务器控件事件的结果才可能在输出页上呈现。如果不运行该检查,仍将为 Page_Load 事件和该页上的任何服务器控件事件执行处理。
并不是所有的应用程序或页都需要针对于具体用户的会话状态,您应该对任何不需要会话状态的应用程序或页禁用会话状态。 若要禁用页的会话状态,请将 @ Page 指令中的 EnableSessionState 属性设置为 false。例如: <%@ Page EnableSessionState="false" %> 注意 如果页需要访问会话变量,但不打算创建或修改它们,则将 @ Page 指令中的 EnableSessionState 属性设置为 ReadOnly。
DataGrid控件带有最强大的数据显示功能,还内置了对数据的修改、删除、添加、分页等很多功能。如果只需简单的显示数据, DataGrid并非最佳选择。DataGrid控件的分页功能,数据的存储方式(存储在viewstate中)等,虽然让程序开发者使用方便快捷,但由 此产生的性能开销不容小视。 DataList控件比DataGrid功能少了很多。但自定义性强了很多。特有的多行数据显示还是比较方便的。DataGrid能实现的功能,它基本能实现。 Repeater控件功能最少,但自定义性非常强。由于减少了很多功能,对服务器的性能带来消耗最小。 因此,在只需简单显示数据列表时,选择Repeater或DataList控件同样可以达到目的,而且减轻了性能上的开销。 建议选择顺序:Repeater然后DataList最后DataGrid(GridView) 6、对数据进行分页 ASP.NET的DataGrid(在asp.net2.0中为GridView)有一个非常有用的功能:分页。如果DataGrid允许分 页,在某一时刻它只下载某一页的数据,另外,它有一个数据分页的浏览导航栏,它让你可以选择浏览某一页,而且每次只下载一页的数据。 但是它有一个小小的缺点,就是你必须把所有的数据都绑定到DataGrid中。也就是说,你的数据层必须返回所有的数据,然后DataGrid 再根据当前页过滤出当前页所需要的数据显示出来。如果有一个一万条记录的结果集要用DataGrid进行分页,假设DataGrid每页只显示25条数 据,那就意味着每次请求都有9975条数据都是要丢弃的。每次请求都要返回这么大的数据集,对应用程序的性能影响是非常大的。 一个好的解决方案是写一个分页的存储过程, CREATE PROCEDURE dbo.sp_DataPages set nocount on if(@Page=1) --print @str 或者,使用sql server 2005中的row_number()函数 declare @sql varchar(8000)
+' select row_number() over (order by id desc) as rowNumber,*' +' )' +' where rowNumber between '+str((@page-1)*@pagesize+1)+' AND '+str(@page*@pagesize) --exec (@sql) 7、不要禁用 Web 窗体页的缓冲 除非有特殊的原因要关闭缓冲,否则使其保持打开。禁用 Web 窗体页的缓冲会导致大量的性能开销。 启用页面输出的缓冲区(Buffer) 使用@Page开关打开页面输出缓冲机制: 使用Web.config或Machine.config配置文件的<pages>节点: 8、设置page的smart navigation属性 smart navigation设置为true能让用户明显的感觉性能提高。启用此属性后对客户端和服务端影响不大.它能智能刷新需要刷新的部分。 在大多数情况下不要在代码中设置该属性。 Internet Explorer 5 或更高版本浏览器请求页时(或稍后),智能导航将通过执行下列功能提高用户对该页的操作能力: 智能导航最适用于需要频繁回发,但是其内容在返回时不会发生显著更改的 ASP.NET 页。在决定是否将该属性设置为 true 时,请仔细考虑这一点。
1、使用值类型的ToString方法 在连接字符串时,经常使用"+"号直接将数字添加到字符串中。这种方法虽然简单,也可以得到正确结果,但是由于涉及到不同的数据类型,数字需要 通过装箱操作转化为引用类型才可以添加到字符串中。但是装箱操作对性能影响较大,因为在进行这类处理时,将在托管堆中分配一个新的对象,原有的值复制到新 创建的对象中。 使用值类型的ToString方法可以避免装箱操作,从而提高应用程序性能。 int num=1;
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 Response.Write(str.ToString); //显示操作结果
采用 Server.Transfer 语法,在页面中使用该方法可避免不必要的客户端重定向(Response.Redirect)。 4、避免使用ArrayList。 因为任何对象添加到ArrayList都要封箱为System.Object类型,从ArrayList取出数据时,要拆箱回实际的类型。建议使用 自定义的集合类型代替ArrayList。asp.net 2.0提供了一个新的类型,叫泛型,这是一个强类型,使用泛型集合就可以避免了封箱和拆箱的发生,提高了性能。 5、使用HashTale代替其他字典集合类型 6、为字符串容器声明常量,不要直接把字符封装在双引号" "里面。 //推荐 7、不要用ToUpper(),ToLower()转换字符串进行比较,用String.Compare代替,它可以忽略大小写进行比较. 8、类型转化Int32.TryParse()优于Int32.Parse()优于Convert.ToInt32()。 建议.NET1.1下用Int32.Parse();.NET2.0用Int32.TryParse()。 9、如果只是从XML对象读取数据,用只读的XPathDocument代替XMLDocument,可以提高性能 //避免 //推荐
//推荐 11、捕获指定的异常,不要使用通用的System.Exception. //避免 12、使用Try...catch...finally时, 要在finally里释放占用的资源如连接,文件流等 try{ 但实际上,Exception是非常消耗系统性能的。除非必要,不应当使用异常控制来实现程序流程。上面的代码应当写为: if(num!=0)
15、禁用VB.net和Jscript动态数据类型 应当始终显示地申明变量数据类型,这能够节约程序的执行时间。以往,开发人员喜欢使用 Visual Basic、VBScript 和 JScript 的原因之一就是它们所谓“无类型”的性质。变量不需要显式类型声明,并能够简单地通过使用来创建它们。当从一个类型到另一个类型进行分配时,转换将自动执 行。不过,这种便利会大大损害应用程序的性能。
1、使用Output Cache缓存数据 提供缓存功能是ASP.net中非常强大的一种功能。曾看到过某些评测说:ASP.net程序的性能比SUN的JSP应用程序性能快上几倍,实际上,该评测程序非常重要的一点就是使用了很多ASP.net的缓存功能。 如果你的组件是要在Asp.net应用程序中运行,你只要把System.Web.dll引用到你的项目中就可以了。然后用HttpRuntime.Cache属性就可访问Cache了(也可以通过Page.Cache或HttpContext.Cache访问)。 有以下几条缓存数据的规则。第一,数据可能会被频繁的被使用,这种数据可以缓存。第二,数据的访问频率非常高,或者一个数据的访问频率不高,但 是它的生存周期很长,这样的数据最好也缓存起来。第三是一个常常被忽略的问题,有时候我们缓存了太多数据,通常在一台X86的机子上,如果你要缓存的数据 超过800M的话,就会出现内存溢出的错误。所以说缓存是有限的。换名话说,你应该估计缓存集的大小,把缓存集的大小限制在10以内,否则它可能会出问 题。在Asp.net中,如果缓存过大的话也会报内存溢出错误,特别是如果缓存大的DataSet对象的时候。 这里有几个你必须了解的重要的缓存机制。首先是缓存实现了“最近使用”原则( a least-recently-used algorithm),当缓存少的时候,它会自动的强制清除那些无用的缓存。其次 “条件依赖”强制清除原则(expiration dependencies),条件可以是时间,关键字和文件。以时间作为条件是最常用的。在asp.net2.0中增加一更强的条件,就是数据库条件。当 数据库中的数据发生变化时,就会强制清除缓存。 使用 ASP.NET 缓存机制有两点需要注意。首先,不要缓存太多项。缓存每个项均有开销,特别是在内存使用方面。不要缓存容易重新计算和很少使用的项。其次,给缓存的项分配 的有效期不要太短。很快到期的项会导致缓存中不必要的周转,并且经常导致更多的代码清除和垃圾回收工作。若关心此问题,请监视与 ASP.NET Applications 性能对象关联的 Cache Total Turnover Rate 性能计数器。高周转率可能说明存在问题,特别是当项在到期前被移除时。这也称作内存压力。 切记: 应该:
1)页面缓存(对整个页面进行缓存) <%//Response.AddHeader("Last-Modified", DateTime.Now.AddHours(-1).ToString("r"));%> <%@Page OutputCache VaryByParams=”classid;page” Duration=”3600” %> .net2.0中为: 你就可以有效的利用第一次请求里生成的页面输出缓存内容,3600秒后重新生成一道页面内容。这种技术其实也是运用一些低层的Cache API来实现。用页面输出缓存有几个参数可以配置,如上面所说的VaryByParams参数,该参数表示什么时候触发重输出的条件,也可以指定在 Http Get或Http Post 请求模式下缓存输出。 例如当我们设置该参数为VaryByParams=”classid;page”的时候,default.aspx?classid=3& page=1 请求的输出都会被缓存起来。没有参数,或不用参数时用none。如果传递的参数不止一个,那么即使字符串参数与值都相同,但排列次序不同,那么在请求页面 时,也将生成不同的缓存页。例如default.aspx?first=1&last=1 和default.aspx?last=1&first=1虽然参数完全相同,但由于排列次序不同,将生成两个不同的缓存页。 许多人都没有意识到当用页面输出缓存的时候,asp.net也会生成HTTP头集(HTTP Header)保存在下游的缓存服务器中,这些信息可以用于Microsoft Internet安全性中以及加速服务器的响应速度。当HTTP缓存的头被重置时,请求的内容会被缓在网络资源中,当客户端再次请求该内容时,就不会再从 源服务器上获得内容了,而直接从缓存中获得内容。 虽然用页面输出缓存不提高你的应用程序性能,但是它能减少了从的服务器中加载已缓存页面内容的次数。当然,这仅限于缓存匿名用户可以访问的页面。因为一旦页面被缓存后,就不能再执行授权操作了。
<%@ OutputCache Duration="60" VaryByParam=”TextBox1;TextBox2” %> 在ASP.net中,除了在页面范围内使用缓存,也还可以针对User Control使用Output Cache参数实现对用户控件的缓存。同样的,一个页面中相同类型的控件也可以有多个不同的缓存。可以根据参数来实现不同的缓存。页面缓存和片断缓存可以同时使用。
数据缓存是一种强大而又非常简单的缓存机制,它可以在缓存区中为每个应用程序保存各种对象,这些对象可以根据http的请求被调用,但是在各个不同的应用程序中这些对象都是私有的。 Cache[“关键字”] = 关键字的取值; 然后通过下面的方法来访问这个对象: string mKeyValue = “”; 注意Page.Cache和HttpContext.Current.Cache区别:
数据缓存的过期依赖条件 某种意义上,Cache和Application是一样的,都是一种公有的对象。为了取得缓存与数据有效性之间的平衡,可以根据需要对缓存过期策略进行合理的设置。
//绝对过期!!!(用来保存公用的,数据量小的数据对象,可以是任何对象) 最后要注意:
虽然Cache API设计成用来保存某段时间的数据,而预请求缓存只是保存某个时期的某个请求的内容。如果某个请求的访问频率高,而且这个请求只需要提取,应用,修改或者更新数据一次。那么就可以预缓存该请求。我们举个例子来说明。 在CS的论坛应用程序中,每一个页面的服务器控件都要求得到用于决定它的皮肤(skin)的自定义的数据,以决定用哪个样式表及其它的一些个性 化的东西。这里面的某些数据可能要长时间的保存,有些时间则不然,如控件的skin数据,它只需要应用一次,而后就可以一直使用。 要实现预请求缓存,用Asp.net 的HttpContext类,HttpContext类的实例在每一个请求中创建,在请求期间的任何地方都可以通过 HttpContext.Current属性访问。HttpContext类有一个Items集合属性,在请求期间所有的对象和数据都被添加到这个集合中 缓存起来。和你用Cache缓存访问频率高数据一样,你可以用HttpContext.Items缓存那些每个请求都要用到的基础数据。它背后的逻辑很简 单:我们向HttpContext.Items中添加一个数据,然后再从它里面读出数据。
|