Use a DataReader
instead of a
DataAdapter
to access the data.
Example 16-7 through Example 16-9 show the .aspx
file and
VB and C# code-behind files for our application that demonstrates the
performance difference between a DataReader
and a
DataAdapter
using the OleDB
managed provider. Figure 16-2 shows the output of
the application. Refer to Recipe 16.4
for an equivalent example using the SQL Server managed provider.
The common language runtime (CLR) provides two primary methods for
reading data from a database. The first is to use a
DataReader
, and the second is to use a
DataAdapter
in conjunction with a
DataTable
or DataSet
.
The DataReader
provides forward, read-only access
to the data read from the database. It provides no mechanisms for
randomly accessing the data.
A DataAdapter
, along with a
DataTable
or DataSet
, provides
random access to data. In addition, the data can be changed in the
DataTable
or DataSet
and the
DataAdapter
can be used to update the data in the
database.
Of the two access methods, the DataReader
is the
lightest and fastest and is preferable when you only need to read the
data, as reflected in the results we show for our sample application
in Figure 16-2. Our example reads 10K and 100K
records from a SQL Server database table containing 500K rows. The
table contains five columns, of which three are retrieved in the
query. The data indicates that using a DataAdapter
is anywhere from 12% to 21% slower than using a
DataReader
.
Example 16-7. Measuring data reader and data adapter performance (.aspx)
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="CH16DataAccessPerformanceVB.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH16DataAccessPerformanceVB" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>Data Access Performance</title> <link rel="stylesheet" href="css/ASPNetCookbook.css"> </head> <body leftmargin="0" marginheight="0" marginwidth="0" topmargin="0"> <form id="frmDataAccessPerformance" method="post" runat="server"> <table width="100%" cellpadding="0" cellspacing="0" border="0"> <tr> <td align="center"> <img src="images/ASPNETCookbookHeading_blue.gif"> </td> </tr> <tr> <td class="dividerLine"> <img src="images/spacer.gif" height="6" border="0"></td> </tr> </table> <table width="90%" align="center" border="0"> <tr> <td align="center"> </td> </tr> <tr> <td align="center" class="PageHeading"> Data Access Performance Using OleDB Provider (VB) </td> </tr> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center"> <table width="100%" align="center" border="0"> <tr> <td align="center">Rows Read</td> <td align="center">OleDBDataReader Time (mSec)</td> <td align="center">OleDBDataAdaptor Time (mSec)</td> </tr> <tr> <td align="center">10,000</td><td id="cellDR10K" runat="server" align="center"></td>
<td id="cellDA10K" runat="server" align="center"></td>
</tr> <tr> <td align="center">100,000</td><td id="cellDR100K" runat="server" align="center"></td>
<td id="cellDA100K" runat="server" align="center"></td>
</tr> </table> </td> </tr> </table> </form> </body> </html>
Example 16-8. Measuring data reader and data adapter performance code-behind (.vb)
Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: CH16DataAccessPerformanceVB.aspx.vb ' ' Description: This module provides the code behind for the ' CH16DataAccessPerformanceVB.aspx page ' '***************************************************************************** Imports Microsoft.VisualBasic Imports System Imports System.Configuration Imports System.Data Imports System.Data.OleDb Namespace ASPNetCookbook.VBExamples Public Class CH16DataAccessPerformanceVB Inherits System.Web.UI.Page 'controls on the form Protected cellDR10K As System.Web.UI.HtmlControls.HtmlTableCell Protected cellDR100K As System.Web.UI.HtmlControls.HtmlTableCell Protected cellDA10K As System.Web.UI.HtmlControls.HtmlTableCell Protected cellDA100K As System.Web.UI.HtmlControls.HtmlTableCell '************************************************************************* ' ' ROUTINE: Page_Load ' ' DESCRIPTION: This routine provides the event handler for the page load ' event. It is responsible for initializing the controls ' on the page. '------------------------------------------------------------------------- Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Dim strConnection As String Dim elapsedTime As TimeSpan 'get the connection string from web.config strConnection = _ ConfigurationSettings.AppSettings("dbConnectionString")'get times for 10,000 records
elapsedTime = getDataAdapterTime(strConnection, 10000)
cellDA10K.InnerText = elapsedTime.TotalMilliseconds.ToString("0.0000")
elapsedTime = getDataReaderTime(strConnection, 10000)
cellDR10K.InnerText = elapsedTime.TotalMilliseconds.ToString("0.0000")
'get times for 100,000 records
elapsedTime = getDataAdapterTime(strConnection, 100000)
cellDA100K.InnerText = elapsedTime.TotalMilliseconds.ToString("0.0000")
elapsedTime = getDataReaderTime(strConnection, 100000)
cellDR100K.InnerText = elapsedTime.TotalMilliseconds.ToString("0.0000")
End Sub 'Page_Load '************************************************************************* ' ' ROUTINE: getDataReaderTime ' ' DESCRIPTION: This routine retrieves the passed number of records from ' the database using an OleDBDataReader and returns the ' elapsed time '-------------------------------------------------------------------------Private Function getDataReaderTime(ByVal strConnection As String, _
ByVal numberOfRecords As Integer) _
As TimeSpan
Dim dbConn As OleDbConnection
Dim dCmd As OleDbCommand
Dim dr As OleDbDataReader
Dim strSQL As String
Dim startTime As DateTime
Dim elapsedTime As TimeSpan
Dim bookTitle As String
Dim isbn As String
Dim price As Decimal
Try
'open connection to database
dbConn = New OleDbConnection(strConnection)
dbConn.Open( )
startTime = DateTime.Now( )
'build the query string and get the data from the database
strSQL = "SELECT Top " & numberOfRecords.ToString( ) & " " & _
"BookTitle, ISBN, Price " & _
"FROM PerformanceTesting " & _
"ORDER BY PerformanceTestingID"
'read the data from the database
dCmd = New OleDbCommand(strSQL, dbConn)
dr = dCmd.ExecuteReader( )
Do While (dr.Read( ))
bookTitle = CStr(dr.Item("BookTitle"))
isbn = CStr(dr.Item("ISBN"))
price = CDec(dr.Item("Price"))
Loop
'return the elapsed time
elapsedTime = DateTime.Now.Subtract(startTime)
getDataReaderTime = elapsedTime
Finally
'clean up
If (Not IsNothing(dbConn)) Then
dbConn.Close( )
End If
End Try
End Function 'getDataReaderTime
'************************************************************************* ' ' ROUTINE: getDataAdapterTime ' ' DESCRIPTION: This routine retrieves the passed number of records from ' the database using an OleDbDataAdapter and returns the ' elapsed time '-------------------------------------------------------------------------Private Function getDataAdapterTime(ByVal strConnection As String, _
ByVal numberOfRecords As Integer) _
As TimeSpan
Dim dbConn As OleDbConnection
Dim da As OleDbDataAdapter
Dim dTable As DataTable
Dim strSQL As String
Dim startTime As DateTime
Dim elapsedTime As TimeSpan
Try
'open connection to database
dbConn = New OleDbConnection(strConnection)
dbConn.Open( )
startTime = DateTime.Now( )
'build the query string and get the data from the database
strSQL = "SELECT Top " & numberOfRecords.ToString( ) & " " & _
"BookTitle, ISBN, Price " & _
"FROM PerformanceTesting " & _
"ORDER BY PerformanceTestingID"
'read the data from the database
da = New OleDbDataAdapter(strSQL, dbConn)
dTable = New DataTable
da.Fill(dTable)
'return the elapsed time
elapsedTime = DateTime.Now.Subtract(startTime)
getDataAdapterTime = elapsedTime
Finally
'clean up
If (Not IsNothing(dbConn)) Then
dbConn.Close( )
End If
End Try
End Function 'getDataAdapterTime
End Class 'CH16DataAccessPerformanceVB
End Namespace
Example 16-9. Measuring data reader and data adapter performance code-behind (.cs)
//---------------------------------------------------------------------------- // // Module Name: CH16DataAccessPerformanceCS.aspx.cs // // Description: This module provides the code behind for the // CH16DataAccessPerformanceCS.aspx page // //**************************************************************************** using System; using System.Configuration; using System.Data; using System.Data.OleDb; namespace ASPNetCookbook.CSExamples { public class CH16DataAccessPerformanceCS : System.Web.UI.Page { // controls on the form protected System.Web.UI.HtmlControls.HtmlTableCell cellDR10K; protected System.Web.UI.HtmlControls.HtmlTableCell cellDR100K; protected System.Web.UI.HtmlControls.HtmlTableCell cellDA10K; protected System.Web.UI.HtmlControls.HtmlTableCell cellDA100K; //************************************************************************ // // ROUTINE: Page_Load // // DESCRIPTION: This routine provides the event handler for the page // load event. It is responsible for initializing the // controls on the page. //------------------------------------------------------------------------ private void Page_Load(object sender, System.EventArgs e) { String strConnection; TimeSpan elapsedTime; // get the connection string from web.config strConnection = ConfigurationSettings.AppSettings["dbConnectionString"];// get times for 10,000 records
elapsedTime = getDataAdapterTime(strConnection, 10000);
cellDA10K.InnerText = elapsedTime.TotalMilliseconds.ToString("0.0000");
elapsedTime = getDataReaderTime(strConnection, 10000);
cellDR10K.InnerText = elapsedTime.TotalMilliseconds.ToString("0.0000");
// get times for 100,000 records
elapsedTime = getDataAdapterTime(strConnection, 100000);
cellDA100K.InnerText = elapsedTime.TotalMilliseconds.ToString("0.0000");
elapsedTime = getDataReaderTime(strConnection, 100000);
cellDR100K.InnerText = elapsedTime.TotalMilliseconds.ToString("0.0000");
} // Page_Load //************************************************************************ // // ROUTINE: getDataReaderTime // // DESCRIPTION: This routine retrieves the passed number of records from // the database using an OleDBDataReader and returns the // elapsed time. //------------------------------------------------------------------------private TimeSpan getDataReaderTime(String strConnection,
int numberOfRecords)
{
OleDbConnection dbConn = null;
OleDbCommand dCmd = null;
OleDbDataReader dr = null;
string strSQL = null;
DateTime startTime;
TimeSpan elapsedTime;
String bookTitle;
String isbn;
Decimal price;
try
{
// open connection to database
dbConn = new OleDbConnection(strConnection);
dbConn.Open( );
startTime = DateTime.Now;
// build the query string used to get the data from the database
strSQL = "SELECT Top " + numberOfRecords.ToString( ) + " " +
"BookTitle, ISBN, Price " +
"FROM PerformanceTesting " +
"ORDER BY PerformanceTestingID";
// read the data from the database
dCmd = new OleDbCommand(strSQL, dbConn);
dr = dCmd.ExecuteReader( );
while (dr.Read( ))
{
bookTitle = (String)(dr["BookTitle"]);
isbn = (String)(dr["ISBN"]);
price = Convert.ToDecimal(dr["Price"]);
}
//return the elapsed time
elapsedTime = DateTime.Now.Subtract(startTime);
return(elapsedTime);
}
finally
{
// clean up
if (dbConn != null)
{
dbConn.Close( );
}
}
} // getDataReaderTime
//************************************************************************ // // ROUTINE: getDataAdapterTime // // DESCRIPTION: This routine retrieves the passed number of records from // the database using an OleDbDataAdapter and returns the // elapsed time. //------------------------------------------------------------------------private TimeSpan getDataAdapterTime(String strConnection,
int numberOfRecords)
{
OleDbConnection dbConn = null;
OleDbDataAdapter da = null;
DataTable dTable = null;
string strSQL = null;
DateTime startTime;
TimeSpan elapsedTime;
try
{
// open connection to database
dbConn = new OleDbConnection(strConnection);
dbConn.Open( );
startTime = DateTime.Now;
// build the query string used to get the data from the database
strSQL = "SELECT Top " + numberOfRecords.ToString( ) + " " +
"BookTitle, ISBN, Price " +
"FROM PerformanceTesting " +
"ORDER BY PerformanceTestingID";
// read the data from the database
da = new OleDbDataAdapter(strSQL, dbConn);
dTable = new DataTable( );
da.Fill(dTable);
// return the elapsed time
elapsedTime = DateTime.Now.Subtract(startTime);
return(elapsedTime);
}
finally
{
// clean up
if (dbConn != null)
{
dbConn.Close( );
}
}
} // getDataAdapterTime
} // CH16DataAccessPerformanceCS }