1 问题的提出
数据库技术与Web技术相结合是当前应用的热点,其中最关键的就是Web数据库访问技术。ADO.NET以ActiveX数据对象(ADO)为基础,但与依赖于连接的ADO不同,ADO.NET是专门为了对数据存储进行无连接数据访问而设计的。
ADO.NET以XML(扩展标记语言)作为传递和接收数据的格式,与ADO相比,它提供了更大的兼容性和灵活性。当前的桌面应用程序大都推出B/S版本,对于Web应用程序,需要大量的访问数据库,如何提高Web数据库访问的效率和性能,是一个现实问题。
本文就ADO.NET在数据存取方面的性能优化,如何得到更快、更可信的数据访问代码进行分析。
2 ADO.NET概述
ADO.NET对象模型有两个核心组件:DataSet和.NET Framework,基本架构见图1。
(1)NET Framework数据提供程序
它是面向连接的,由一组对象组成,包括Connec-tion,Command,DataReader和DataAdapter等核心对象。主要功能为:连接到数据源,以便检索和修改数据源中的数据,并在数据源和DataSet之间起着桥梁的作用。
(2)DataSet
DataSet是ADO.NET的中心概念.可以把DataSet当成内存中的数据库,DataSet是不依赖于数据库的独立数据集合。即使断开数据链路,或者关闭数据库,DataSet依然是可用。DataSet在内部是用XML描述数据,由于XML是一种与平台无关、与语言无关的数据描述语言,而且可以描述复杂关系的数据,所以DataSet可以容纳具有复杂关系的数据,而且不在依赖于数据库链路。DataSet是数据的内存驻留表示形式,无论数据源是什么,它都会提供一致的关系编程模型;它可以用于多个不同的数据源,用于XML数据,或用于管理应用程序本地的数据。DataSet表示包括相关表、约束和表间关系在内的整个数据集,通过DataAda-pter控制其与现有数据源的交互。
3 ADO.NET性能优化模型
要开发出一个能以有效的方式来检索和存取数据的ASP.NET应用程序,就应该编写高效率高性能经过优化的ADO.NET数据访问代码,充分发挥ADO.NET的优势。为达到这一目的,需要对ADO.NET的不同优化技术和使用方法进行全面的分析,并给出客观的性能测试,特别是数据存取性能上。
ADO.NET数据访问的性能优化内容如图2所示,即:连接池的性能分析;.NET数据提供程序选择比较使用;DataReader,DataSet和RecordSet的性能比较分析;存储过程的性能分析;DataSet和DataReader的调用细节性能分析等。
3.1 连接池的性能分析
对于要访问数据库的ASP.NET、应用程序,需要建立到数据库的连接并使用该连接进行数据存取。然而,与数据库建立连接要花费相对较长的时间进行协商,数据库连接也会消耗宝贵的系统资源如CPU处理能力、内存和网络带宽等。
解决办法:使用连接池技术(connection pooling),用来加速连接过程和避免浪费系统资源。连接池是一组简单的带有类似于连接字符串的连接。在开发一个多层应用程序时,有效地利用连接池可以提高应用程序的性能。图3展示了一个带连接池的多层应用程序。
ADO.NET中的连接池非常简单,在ADO.NET中的每个.NET数据提供程序(SQL Server和OLE DB)都可实现连接池。当请求一个新连接时,.NET数据提供程序会检查该请求已提供的凭据(数据库位置、用户名等),并在池中以匹配凭据的方式搜索打开的连接,如果找到有这样的一个连接,就将该连接递交给该请求;否则就只有创建并返回一个新建的连接。
当关闭连接对象时,.NET数据提供程序并不真正的关闭实际的数据库连接。它将连接对象标记为已关闭,并将其存储在连接池中。如果该数据库连接在特定的时间内未被再次使用,.NET数据提供程序就会真正的关闭此连接。
表1展示了有无连接池情况下,连续循环1 000次,建立连接(打开后马上关闭)所需要的时间对比。
以上测试数据非常明显表明:带有连接池的数据库访问应用程序其代价要小得多,其性能高得多。
3.2 ADO.NET数据提供者比较
要访问不同的数据源,选择适当的数据提供者,对性能的影响很大。
.NET数据提供者是处理特定类型的数据库的一组类“集”。所有的数据提供者都必须提供一组基本的功能,但不同的数据提供者可能有许多额外的属性和方法,只能被用来访问某一特定的数据存储。也就是说不同的数据提供者是对不同的数据存储类型进行专门的优化,使得其访问不同的数据源有不同的运行效率和性能。.NET架构共提供了4种数据提供程序,他们是:SQL Client,OLE DB,ODBC,Oracle Client数据提供程序。其中SQL CLient数据提供程序是专门针对SQL Server 7.0及以上版本作了优化。
SQL Client.NET数据提供程序:用于使用SQLServer 7.0及更高版本的中间层和单层应用程序;用于SQL Server的OLE DB提供程序(SQLOLEDB)与OLE DB.NET数据提供程序一起使用。OLE DB.NET数据提供程序:用于使用SQL Server 6.5或较早版本的中间层应用程序,或任何支持OLE DB.NET数据提供程序所使用的OLE DB接口中所列OLE DB接口(不支持OLE DB 2.5接口)的OLE DB提供程序;使用Access数据库的单层应用程序。ODBC.NET数据提供程序:用于使用ODBC数据源的中间层应用程序和单层应用程序。Oracle.NET数据提供程序:用于使用Oracle数据源的中间层应用程序和单层应用程序;支持Oracle客户端软件8.1.7版和更高版本。
测试及分析:分别用SQL Client.NET,OLE DB.NET,ODBC.NET,Oracle.NET数据提供程序(由于不能访问SQL Server数据库,未作考虑)分别去连接SQL Server数据库,并完成相关的连接、检索(简单的)、更改操作,测试其运行的效率。完成3项的测试内容为:
分别连接数据库所需时间,即cnn.open();分别从数据库中去检索出200 000条记录所需的时间,采用的方式是用DataAdapter去将数据检索出来并填充到相应的数据集(DataSet)中;分别对这200 000条记录中每条记录都更新一个字段值。通过命令的Exe-cuteNonQuery方法实现。运行结果见表2。
分析:从上表可以看出,SQL Client.NET效率最高,OLE DB.NET次之,ODBC.NET最慢。当数据库为SQL Server 2000时,无论是在数据库连接、数据提取、数据更新方面,SQL Client.NET提供程序执行效率都比OLE DB.NET提供程序和ODBC.NET提供程序都具有非常明显的优势。因此当连接微软SQLServer数据库时,建议采用SQL Client.NET数据提供程序访问数据库;而对于ORACLE数据库,则采用Oraele Client.NET提供程序;对于Sybase,Informix,DB2,Access等数据库则采用OLE DB.NET提供程序来连接。
3.3 存储过程的性能优化
使用存储过程与直接使用SQL语句相比具有事务处理、执行速度、进程控制、安全性、减少网络通信流量、模块化等优势。
对存储过程的使用可以通过DataAdapter对象执行存储过程将数据送到DataSet或送往数据库;或直接通过Command对象执行存储过程将数据送到DataReader、界面或数据库中去。它们都可以使用参数对象向存储过程传递参数。
下面通过使用存储过程和直接传递SQL语句来进行测试比较;
分析:其实上面的测试代码并没有完全发挥出存储过程的优势,但可以看出它们之间的性能差别。存储过程通常是数据库交互的首选方法,尽管存储过程很多优点,但仍有某些情况不适合使用存储过程。存储过程存在的主要问题是可扩展性。
3.4 DataReader,DataSet和RecordSet性能比较
DataReader提供对来自数据源的数据流的只读,只向前访问;主要用于读取数据以填充像标签、列表或者DataGrid之类的数据感知控件,并最小限度使用资源,适合Web应用程序(无状态应用)。
DataSet专门针对断开连接开发的,用作数据的本地存储机制,为数据源提供一个本地的不连接的副本,通过DataAdapter与数据源保持同步,也可以用作独立的数据存储对象。主要用途:显示复杂的数据(来自于多个数据源或者相关数据)、写(编辑、创建、删除、写回)数据源中的数据。
RecordSet为目前大量存在的使用ADO的应用程序而提供的向前兼容版本。
三种形式在ASP.NET应用程序中的测试和分析:
测试内容:针对Northwind数据库中的Orders和Order Details两个表的内连来查询数据。其中Orders表的记录为830条。使用SQL server.net提供程序连接SQL Server。
循环100次测试的结果见表4。
对于Web应用程序而言,一般不会出现重复读取完整的缓存中的数据集,因为Web应用程序这样的无状态的程序,是不能利用由DataSet提供的高速缓存。
在ASP.NET中,DataReader效率最高,将数据从数据库中提取到内存中,DataSet的填充最耗时,但如果对于桌面程序,可能要反复使用缓存中的数据,这时DataSet效率最高,因为它耗时最小,这也是DataSet为断开的连接而开发的主要原因。
3.5 DataSet和DataReader的调用性能
ADO.NET中不同的调用方法、属性使用、数据类型使用都存在不同的性能差异。主要有:
(1)基于名称或序号对数据元素的访问
使用基于名称的访问,DataReader要根据提供的字符串在其内部结构中定位该列,它要对结果集中的每行都要执行一个基于字符串的查找,必然浪费一定的性能;使用基于序号或索引的访问,性能要高一些。
(2)使用适当的类型指定Get方法
使用与结果集中列返回的数据相对应的类型指定Get方法,可以提高应用程序性能。如DataReaderInstance.GetValue(i).ToString()与DataReaderInstance.GetString(i)在执行效率上是不同的。前者返回的是Ob-ject类型,还必须将其转换为字符串数据。而后者直接返回的是字符串数据,无须转换,性能当然会提高。
下面分别按名称和索引循环从库中取数据,结果见表5。
数据测试结果见表所示,从测试数据也说明DataSet和DataReader在使用上的性能优化差异。
4 结 语
对于ASP.NET应用程序而言,要开发出速度更快更可信的数据访问代码,提高数据访问性能,应该就其模型进行优化,在连接池,.NET数据提供者的选择,存储过程的使用,DataReader,DataSet和RecordSet的选择及其具体的调用方法等方面作出优化的选择。从而使系统的性能得到改善。