性能优化方法
1.1使用会话状态
ASP.NET使用3种方法存储会话状态:存储在进程中;存储在状态服务器中;或者存储在SQL Server数据库中。将状态信息存储在进程中。此时,会话状态信息将保存在Web服务器的内存中,而不能和其他系统进行共享。这种存储方式具有最佳的性能,速度最快,因为不需要和其他系统通信以取得会话信息。但是,这种存储方式放弃了绘画状态信息跨越多台服务器的能力。
在Web。config文件的sessionState字段中对话状态进行设置,将mode属性设为InProc即为选择存储在进程中。改变TimeOut属性即可改变超时时间,其单位为分钟。相关实现代码如下所示:
如果需要在多个Web服务器之间维护会话信息,将使用状态服务器来对其进行存储。选择状态服务器将会引入额外的工作负载,因为在每次用户情求一个页面时,会话信息将不在时直接从Web服务器获得,必须由Web服务器向状态服务器发送请求。虽然这种方式造成了性能降低,但是由于可以将应用程序部署到多台服务器上而提高了系统的伸缩性和可靠性。下面是使用状态服务器的sessionState状态设置。其中stateNetworkTimeout属性表示连接状态服务器超时时间,默认时间为10秒钟。假如超过该时间还未与状态服务器连接将产生页面错误。减少该时间可以减少用户的等待时间,但会增加状态服务器的负担,需要慎重设置。状态服务器sessionState代码如下所示:
对于极其重要的会话信息,应该使用SQL Server存储方式。同以上两种方式相比,使用SQL Server服务器跟踪会话产生的工作负载更大。但是使用状态服务器仅仅实现了应用程序部署在多台服务器,会话信息本身还是集中保存在状态服务器上。假如状态服务器出现异常会话信息将会丢失。而使用SQL Server能够设置冗余服务器避免会话信息丢失的情况。下面是使用SQL Server存储的sessionState设置代码:
从另一个角度来说,并非所有的页面都需要保存用户的会话状态。如果没有必要,完全可以在页面的级别将其完全禁用,使用以下代码即可实现:
<%@Page EnableSessionState="false"%>
如果页面需要访问会话变量但不创建或修改它们,可以将EnableSessionState设置为ReadOnly。这些在一定程度上提高了Web应用程序的性能。
1.2使用Page。isPostback
使用Page。isPostback可以避免往返过程中的不必要工作。不仅仅对于Page_Load函数,对于其他需要初始化一次的事件函数也可以使用Page。isPostback来提高性能。
1.3使用服务器控件
1、避免使用服务器控件
2、禁用服务器控件的状态的试图
视图状态能够自动在页面往返过程中维护服务区控件的状态,减少开发者的工作量,但是这付出了性能上的代价。因此,在不需要的时候,应该将服务器控件的EnableViewState属性设为false。假如页面上的所有服务器控件都不需要视图状态,可以将页面设为禁用视图状态:
<%@Page EnableViewState="false"%>
3、避免使用DataGrid
1.4字符串操作
1、避免装箱操作
进行字符串操作时,经常直接使用“+”将数字添加到字符串中。由于数字为值类型,要通过装箱操作转化为引用类型才能添加到字符串中。对值类型进行装箱操作时,将在托管堆中分配一个新对象,原来的值复制到创建的新对象中。因此装箱操作将会极大地影响性能。使用值类型的ToString方法可以避免装箱操作,从而提高性能。如:
2、使用StringBuilder类
上面通过使用值类型的ToString方法避免装箱操作提高性能。但是由于String类对象是不可以改变的,一旦创建就无法再对它的值进行修改。对于String的重新赋值在本质上是从新创建了一个String对象并将其赋给被赋值对象。使用StringBuilder类可以避免从新创建String对象造成的性能损失,通过StringBuilder类对象的Append,Remove,Insert等方法可以得到与直接操作String对象相同的效果,修改完成后使用ToString方法即可得到需要的字符串。如:
1.5数据访问
1、数据库连接
经常打开、关闭数据库连接会严重影响应用程序的性能。为了解决这个问题,ASP.NET提供了连接池来对数据库连接进行操作,减少频繁打开、关闭数据库连接对性能的影响。既然ASP.NET已经解决了这个问题,对于数据库连接还需要什么性能优化呢?由于连接池的大小是由限制的,如果达到了连接池的最大限制后要继续创建连接,将被迫等待连接池中的空间。因此,要尽量推迟打开数据库连接,在数据库操作完成后及时关闭连接,从而减少数据库连接打开的时间。示例代码:
2、数据库查询
(1)直接生成SQL语句字符串,将其作为SqlCommand对象的CommandText属性。示例代码如下:
对于这样的查询命令,SQL Server需要每次对其进行编译,在性能方面自然不会有很好的表现,同时还会带来安全隐患。用户可以自己将自己的输入与原来的数据库语句结合成新的SQL语句,对数据库进行非法操作,因此需要避免。
(2)使用带有参数的SQL命令。示例代码如下:
使用这种方式对数据库进行查询,SQL Server就能够只对命令编译一次,对于不同的参数重复使用,提高老性能。
(3)使用SQL Server存储过程。
使用存储过程不仅可以避免对命令的多次编译,而且可以独立于程序,便于修改,不需要从新编译程序。最重要的是还可以减少网络中的数据传送,进一步提高性能。
ASP.NET使用3种方法存储会话状态:存储在进程中;存储在状态服务器中;或者存储在SQL Server数据库中。将状态信息存储在进程中。此时,会话状态信息将保存在Web服务器的内存中,而不能和其他系统进行共享。这种存储方式具有最佳的性能,速度最快,因为不需要和其他系统通信以取得会话信息。但是,这种存储方式放弃了绘画状态信息跨越多台服务器的能力。
在Web。config文件的sessionState字段中对话状态进行设置,将mode属性设为InProc即为选择存储在进程中。改变TimeOut属性即可改变超时时间,其单位为分钟。相关实现代码如下所示:
1 <sessionState
2 mode="InProc"
3 stateConnectionString="tcpip=127.0.0.1:42424"
4 stateNetworkTimeOut="10"
5 sqlConnectionString="data source=127.0.0.1;user id=sa;password="
6 cookieless="false"
7 timeout="20"/>
2 mode="InProc"
3 stateConnectionString="tcpip=127.0.0.1:42424"
4 stateNetworkTimeOut="10"
5 sqlConnectionString="data source=127.0.0.1;user id=sa;password="
6 cookieless="false"
7 timeout="20"/>
1 <sessionState
2 mode="StateServer"
3 stateConnectionString="tcpip=StateServerIP:42424"
4 stateNetworkTimeout="10"
5 cookieless="false"
6 timeout="20"/>
2 mode="StateServer"
3 stateConnectionString="tcpip=StateServerIP:42424"
4 stateNetworkTimeout="10"
5 cookieless="false"
6 timeout="20"/>
1 <sessionState
2 mode="SqlServer"
3 sqlConnectionString="data source=SQLServerIP;user id=SqlUsername;password=SqlPassword"
4 stateNetworkTimeout="10"
5 cookieless="false"
6 timeout="20"/>
2 mode="SqlServer"
3 sqlConnectionString="data source=SQLServerIP;user id=SqlUsername;password=SqlPassword"
4 stateNetworkTimeout="10"
5 cookieless="false"
6 timeout="20"/>
<%@Page EnableSessionState="false"%>
如果页面需要访问会话变量但不创建或修改它们,可以将EnableSessionState设置为ReadOnly。这些在一定程度上提高了Web应用程序的性能。
1.2使用Page。isPostback
使用Page。isPostback可以避免往返过程中的不必要工作。不仅仅对于Page_Load函数,对于其他需要初始化一次的事件函数也可以使用Page。isPostback来提高性能。
1.3使用服务器控件
1、避免使用服务器控件
2、禁用服务器控件的状态的试图
视图状态能够自动在页面往返过程中维护服务区控件的状态,减少开发者的工作量,但是这付出了性能上的代价。因此,在不需要的时候,应该将服务器控件的EnableViewState属性设为false。假如页面上的所有服务器控件都不需要视图状态,可以将页面设为禁用视图状态:
<%@Page EnableViewState="false"%>
3、避免使用DataGrid
1.4字符串操作
1、避免装箱操作
进行字符串操作时,经常直接使用“+”将数字添加到字符串中。由于数字为值类型,要通过装箱操作转化为引用类型才能添加到字符串中。对值类型进行装箱操作时,将在托管堆中分配一个新对象,原来的值复制到创建的新对象中。因此装箱操作将会极大地影响性能。使用值类型的ToString方法可以避免装箱操作,从而提高性能。如:
1 string test="";
2 for(int i=0;i<10000;i++)
3 //test = test + i;
4 test = test + i.ToString();
2 for(int i=0;i<10000;i++)
3 //test = test + i;
4 test = test + i.ToString();
上面通过使用值类型的ToString方法避免装箱操作提高性能。但是由于String类对象是不可以改变的,一旦创建就无法再对它的值进行修改。对于String的重新赋值在本质上是从新创建了一个String对象并将其赋给被赋值对象。使用StringBuilder类可以避免从新创建String对象造成的性能损失,通过StringBuilder类对象的Append,Remove,Insert等方法可以得到与直接操作String对象相同的效果,修改完成后使用ToString方法即可得到需要的字符串。如:
1 System.Text.StringBuilder test = new System.Text.StringBuilder();
2 for(int i=0;i<10000;i++)
3 test.Append(i.ToString());
2 for(int i=0;i<10000;i++)
3 test.Append(i.ToString());
1、数据库连接
经常打开、关闭数据库连接会严重影响应用程序的性能。为了解决这个问题,ASP.NET提供了连接池来对数据库连接进行操作,减少频繁打开、关闭数据库连接对性能的影响。既然ASP.NET已经解决了这个问题,对于数据库连接还需要什么性能优化呢?由于连接池的大小是由限制的,如果达到了连接池的最大限制后要继续创建连接,将被迫等待连接池中的空间。因此,要尽量推迟打开数据库连接,在数据库操作完成后及时关闭连接,从而减少数据库连接打开的时间。示例代码:
1 DataSet ds = new DataSet();
2 string SqlName = "SalesByCategory";
3 SqlConnection MyConnection = new SqlConnection("server=localhost;uid=sa;pwd=;database=NorthWind");
4 SqlCommand GetCMD = new SqlCommand(SqlName,MyConnection);
5 GetCMD.CommandType = CommandType.StoredProcedure;
6 SqlParameter ParaID = new SqlParameter("@CategoryName",SqlDbType.NVarChar,15);
7 ParaID.Value = "";
8 GetCMD.Parameters.Add(ParaID);
9 SqlParameter ParaSender = new SqlParameter("@OrdYear",SqlDbType.NVarChar,4);
10 ParaSender.Value = "";
11 GetCMD.Parameters.Add(ParaSender);
12 SqlDataAdapter adapter = new SqlDataAdapter(SqlName,MyConnection);
13 adapter.SelectCommand = GetCMD;
14 MyConnection.Open();
15 adapter.Fill(ds);
16 MyConnection.Close();
17 ds.Tables[0].Rows.RemoveAt(ds.Tables[0].Rows.Count-i);
2 string SqlName = "SalesByCategory";
3 SqlConnection MyConnection = new SqlConnection("server=localhost;uid=sa;pwd=;database=NorthWind");
4 SqlCommand GetCMD = new SqlCommand(SqlName,MyConnection);
5 GetCMD.CommandType = CommandType.StoredProcedure;
6 SqlParameter ParaID = new SqlParameter("@CategoryName",SqlDbType.NVarChar,15);
7 ParaID.Value = "";
8 GetCMD.Parameters.Add(ParaID);
9 SqlParameter ParaSender = new SqlParameter("@OrdYear",SqlDbType.NVarChar,4);
10 ParaSender.Value = "";
11 GetCMD.Parameters.Add(ParaSender);
12 SqlDataAdapter adapter = new SqlDataAdapter(SqlName,MyConnection);
13 adapter.SelectCommand = GetCMD;
14 MyConnection.Open();
15 adapter.Fill(ds);
16 MyConnection.Close();
17 ds.Tables[0].Rows.RemoveAt(ds.Tables[0].Rows.Count-i);
(1)直接生成SQL语句字符串,将其作为SqlCommand对象的CommandText属性。示例代码如下:
1 SqlCommand GetCMD = new SqlCommand(SqlName,MyConnection);
2 String SelectCMD = "Select * From Employees";
3 SelectCMD = SelectCMD + "Where(EmployeeID = '"+txtEmployee.Text+"')";
4 GetCMD.CommandText = SelectCMD;
2 String SelectCMD = "Select * From Employees";
3 SelectCMD = SelectCMD + "Where(EmployeeID = '"+txtEmployee.Text+"')";
4 GetCMD.CommandText = SelectCMD;
(2)使用带有参数的SQL命令。示例代码如下:
1 SqlCommand GetCMD = new SqlCommand(SqlName,MyConnection);
2 String SelectCMD = "Select * From Employees Where EmployeeID = @EID";
3 SqlParameter ParaID = new SqlParameter("@EID",SqlDbType.Int,4);
4 ParaID.Value = 3;
5 GetCMD.Parameters.Add(ParaID);
6 GetCMD.CommandText = SelectCMD;
2 String SelectCMD = "Select * From Employees Where EmployeeID = @EID";
3 SqlParameter ParaID = new SqlParameter("@EID",SqlDbType.Int,4);
4 ParaID.Value = 3;
5 GetCMD.Parameters.Add(ParaID);
6 GetCMD.CommandText = SelectCMD;
(3)使用SQL Server存储过程。
使用存储过程不仅可以避免对命令的多次编译,而且可以独立于程序,便于修改,不需要从新编译程序。最重要的是还可以减少网络中的数据传送,进一步提高性能。