認識并測量Typed DataSet Truly 2005-08-05 下載本文的源碼(C#) - 17k 下載本文的源碼(VB) - 15k 簡介 強類型DataSet 強類型DataSet是從DataSet繼承的定制對象,它可以通過其顯露的屬性(properties)來對封裝數據進行強類型的訪問。 強類型DataSet避免了字段的晚綁定。強類型DataSet提供了強類型的訪問器,因為避免了到一個集合中查找列名或表名,訪問時更快。 除了能夠提高運行時的性能,強類型DataSet還提供了類型檢查,并且在設計時可以通過自定義字段名對字段智能感知。 在實例化和封送的性能上,強類型的DataSet和普通的DataSet大致相當。主要的性能優勢在于客戶端可以直接訪問方法和屬性而毋須通過集合。 創建Typed DataSet 這里借用MSDN的一篇文章http://support.microsoft.com/default.aspx?scid=kb;en-us;320714 簡單的說就是在項目上點右鍵—》添加新項-》數據集-》取名dsProducts,然后在從服務器資源管理器中將sqlserver展開找到Northwind的Alphabetical list of products視圖拖入dsProducts的設計窗口-》保存。 性能測量 好啦,下面我們對通過兩個簡單的頁面來對常規DataSet和Typed DataSet進行一下性能比較 完整源碼(NormalDataSet.aspx) | <%@ Page language="c#" Codebehind="NormalDataSet.aspx.cs" AutoEventWireup="false" Inherits="STD.NormalDataSet" %>
<!DOCTYPE html public "-//w3c//dtd html 4.0 transitional//en" >
<HTML><HEAD><TITLE>NormalDataSet</TITLE><META name="GENERATOR" content="Microsoft Visual Studio .NET 7.1"><META name="CODE_LANGUAGE" content="C#"><META name=vs_defaultClientScript content="JavaScript"><META name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5"></HEAD><BODY ms_positioning="GridLayout"><FORM id="Form1" method="post" runat="server"><ASP:LABEL id=Label1 style="Z-INDEX: 101; LEFT: 250px; POSITION: absolute; TOP: 250px" runat="server" /></FORM></BODY>
</HTML>
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="NormalDataSet.aspx.vb" Inherits="STDvb.NormalDataSet"%>
<!DOCTYPE html public "-//w3c//dtd html 4.0 transitional//en">
<HTML><HEAD><TITLE>NormalDataSet</TITLE><META name="GENERATOR" content="Microsoft Visual Studio .NET 7.1"><META name="CODE_LANGUAGE" content="Visual Basic .NET 7.1"><META name=vs_defaultClientScript content="JavaScript"><META name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5"></HEAD><BODY ms_positioning="GridLayout"><FORM id="Form1" method="post" runat="server"><ASP:LABEL id=Label1 style="Z-INDEX: 101; LEFT: 250px; POSITION: absolute; TOP: 250px" runat="server" /></FORM></BODY>
</HTML>
| | C# | VB | 隱藏代碼 | ? |
完整源碼(NormalDataSet.aspx.cs/vb) | using System;
using System.Data;
using System.Data.SqlClient;
namespace STD
{/// <SUMMARY>/// WebForm2 的摘要說明。/// </SUMMARY>public class NormalDataSet : System.Web.UI.Page{protected System.Web.UI.WebControls.Label Label1;private void Page_Load(object sender, System.EventArgs e){SqlConnection cn = new SqlConnection("server=localhost;uid=sa;pwd=;database=northwind");SqlCommand cmd = new SqlCommand("select * from [Alphabetical list of products]", cn);SqlDataAdapter da = new SqlDataAdapter(cmd);DataSet tds = new DataSet();da.Fill(tds);long begin = DateTime.Now.Ticks;// 放大性能差異for(int k =0;k<10000;k++){for(int i = 0,j = tds.Tables[0].Rows.Count;i<J;i++){label1.text = tds.Tables[0].Rows[i]["ProductName"].ToString();}}long end = DateTime.Now.Ticks;response.write("Total Time(ms): " + (end- begin));}#region web 窗體設計器生成的代碼override protected void oninit(eventargs e){//// CODEGEN: 該調用是 asp.net web 窗體設計器所必需的。//initializecomponent();base.oninit(e);}/// <SUMMARY>/// 設計器支持所需的方法 - 不要使用代碼編輯器修改/// 此方法的內容。/// </SUMMARY>private void InitializeComponent(){ this.Load += new System.EventHandler(this.Page_Load);}#endregion}
}
Imports System.Data.SqlClient
Public Class NormalDataSetInherits System.Web.UI.Page#Region " Web 窗體設計器生成的代碼 "'該調用是 Web 窗體設計器所必需的。<SYSTEM.DIAGNOSTICS.DEBUGGERSTEPTHROUGH()> Private Sub InitializeComponent()End SubProtected WithEvents Label1 As System.Web.UI.WebControls.Label'注意: 以下占位符聲明是 Web 窗體設計器所必需的。'不要刪除或移動它。Private designerPlaceholderDeclaration As System.ObjectPrivate Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init'CODEGEN: 此方法調用是 Web 窗體設計器所必需的'不要使用代碼編輯器修改它。InitializeComponent()End Sub#End RegionPrivate Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.LoadDim cn As SqlConnection = New SqlConnection("server=localhost;uid=sa;pwd=;database=northwind")Dim cmd As SqlCommand = New SqlCommand("select * from [Alphabetical list of products]", cn)Dim da As SqlDataAdapter = New SqlDataAdapter(cmd)Dim tds As DataSet = New DataSetda.Fill(tds)Dim lngBegin As Long = DateTime.Now.Ticks' 放大性能差異Dim k, i As IntegerFor k = 0 To 10000For i = 0 To tds.Tables(0).Rows.Count - 1Label1.Text = tds.Tables(0).Rows(i)("ProductName").ToString()NextNextDim lngEnd As Long = DateTime.Now.TicksResponse.Write("Total Time(ms): " & (lngEnd - lngBegin))End SubEnd Class | | C# | VB | 隱藏代碼 | ? |
完整源碼(TypedDataSet.aspx) | <%@ Page language="c#" Codebehind="TypedDataSet.aspx.cs" AutoEventWireup="false" Inherits="STD.TypedDataSet" %>
<!DOCTYPE html public "-//w3c//dtd html 4.0 transitional//en" >
<HTML><HEAD><TITLE>TypedDataSet</TITLE><META name="GENERATOR" content="Microsoft Visual Studio .NET 7.1"><META name="CODE_LANGUAGE" content="C#"><META name=vs_defaultClientScript content="JavaScript"><META name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5"></HEAD><BODY ms_positioning="GridLayout"><FORM id="Form1" method="post" runat="server"><ASP:LABEL id=Label1 style="Z-INDEX: 101; LEFT: 250px; POSITION: absolute; TOP: 250px" runat="server" /></FORM></BODY>
</HTML>
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="TypedDataSet.aspx.vb" Inherits="STDvb.TypedDataSet"%>
<!DOCTYPE html public "-//w3c//dtd html 4.0 transitional//en">
<HTML><HEAD><TITLE>TypedDataSet</TITLE><META name="GENERATOR" content="Microsoft Visual Studio .NET 7.1"><META name="CODE_LANGUAGE" content="Visual Basic .NET 7.1"><META name=vs_defaultClientScript content="JavaScript"><META name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5"></HEAD><BODY ms_positioning="GridLayout"><FORM id="Form1" method="post" runat="server"><ASP:LABEL id=Label1 style="Z-INDEX: 101; LEFT: 250px; POSITION: absolute; TOP: 250px" runat="server" /></FORM></BODY>
</HTML>
| | C# | VB | 隱藏代碼 | ? |
完整源碼(TypedDataSet.aspx.cs/TypedDataSet.aspx.vb) | using System;
using System.Data.SqlClient;namespace STD
{/// <SUMMARY>/// WebForm1 的摘要說明。/// </SUMMARY>public class TypedDataSet : System.Web.UI.Page{protected System.Web.UI.WebControls.Label Label1;private void Page_Load(object sender, System.EventArgs e){SqlConnection cn = new SqlConnection("server=.;uid=sa;pwd=;database=northwind");SqlCommand cmd = new SqlCommand("select * from [Alphabetical list of products]", cn);SqlDataAdapter da = new SqlDataAdapter(cmd);dsProducts tds = new dsProducts();da.Fill(tds, tds.Tables[0].TableName);long begin = DateTime.Now.Ticks;// 放大性能差異for(int k =0;k<10000;k++){for(int i = 0,j = tds.Alphabetical_list_of_products.Rows.Count;i<J;i++){label1.text = tds.Alphabetical_list_of_products[i].ProductName;}}long end = DateTime.Now.Ticks;response.write( end- begin);}#region web 窗體設計器生成的代碼override protected void oninit(eventargs e){//// CODEGEN: 該調用是 asp.net web 窗體設計器所必需的。//initializecomponent();base.oninit(e);}/// <SUMMARY>/// 設計器支持所需的方法 - 不要使用代碼編輯器修改/// 此方法的內容。/// </SUMMARY>private void InitializeComponent(){ this.Load += new System.EventHandler(this.Page_Load);}#endregion}
}
Imports System.Data.SqlClient
Public Class TypedDataSetInherits System.Web.UI.Page
#Region " Web 窗體設計器生成的代碼 "'該調用是 Web 窗體設計器所必需的。<SYSTEM.DIAGNOSTICS.DEBUGGERSTEPTHROUGH()> Private Sub InitializeComponent()End SubProtected WithEvents Label1 As System.Web.UI.WebControls.Label'注意: 以下占位符聲明是 Web 窗體設計器所必需的。'不要刪除或移動它。Private designerPlaceholderDeclaration As System.ObjectPrivate Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init'CODEGEN: 此方法調用是 Web 窗體設計器所必需的'不要使用代碼編輯器修改它。InitializeComponent()End Sub#End RegionPrivate Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.LoadDim cn As SqlConnection = New SqlConnection("server=localhost;uid=sa;pwd=;database=northwind")Dim cmd As SqlCommand = New SqlCommand("select * from [Alphabetical list of products]", cn)Dim da As SqlDataAdapter = New SqlDataAdapter(cmd)Dim tds As dsProducts = New dsProductsda.Fill(tds, tds.Tables(0).TableName)Dim lngBegin As Long = DateTime.Now.Ticks' 放大性能差異Dim k, i As IntegerFor k = 0 To 10000For i = 0 To tds.Alphabetical_list_of_products.Rows.Count - 1Label1.Text = tds.Alphabetical_list_of_products(i).ProductNameNextNextDim lngEnd As Long = DateTime.Now.TicksResponse.Write("Total Time(ms): " & (lngEnd - lngBegin))End SubEnd Class | | C# | VB | 隱藏代碼 | ? |
測試結果(受操作系統,硬件環境,框架版本等影響,僅供參考) 注:以下結果是從頁面運行結果取10次數值所得 | 頁面 | 平均 | 最小 | | NormalDataSet.aspx(C#) | 4687500 | 4375000 | | NormalDataSet.aspx(VB) | 4687500 | 4687500 | | TypedDataSet.aspx(C#) | 2500000 | 2343750 | | TypedDataSet.aspx(VB) | 3437500 | 3281250 |
典型的ACT測試結果(只對C#進行了測試,vb的頁面請自行測試比較 | 屬性 測試類型: 動態 瀏覽器同時連接數: 1 準備時間(秒): 測試持續時間: 00:00:05:00 測試迭代次數: 586 生成的詳細測試結果: 是 摘要 請求總數: 586 連接總數: 586 每秒平均請求數: 1.95 首字節平均響應時間(毫秒): 510.41 末字節平均響應時間(毫秒): 510.48 每次迭代末字節平均響應時間(毫秒): 510.48 測試中的唯一請求數: 1 唯一響應代碼數: 1 錯誤計數 HTTP: DNS: 套接字: 其他網絡統計數據 平均帶寬(字節/秒): 2,730.95 發送字節數(字節): 147,234 接收字節數(字節): 672,050 發送字節平均速率(字節/秒): 490.78 接收字節平均速率(字節/秒): 2,240.17 連接錯誤數: 發送錯誤數: 接收錯誤數: 超時錯誤數: 響應代碼 Response Code: 200 - 請求已成功完成。 計數: 586 百分比(%): 100.00
屬性 測試類型: 動態 瀏覽器同時連接數: 1 準備時間(秒): 測試持續時間: 00:00:05:00 測試迭代次數: 1,124 生成的詳細測試結果: 是 摘要 請求總數: 1,124 連接總數: 1,124 每秒平均請求數: 3.75 首字節平均響應時間(毫秒): 265.19 末字節平均響應時間(毫秒): 265.27 每次迭代末字節平均響應時間(毫秒): 265.27 測試中的唯一請求數: 1 唯一響應代碼數: 1 錯誤計數 HTTP: DNS: 套接字: 其他網絡統計數據 平均帶寬(字節/秒): 6,819.44 發送字節數(字節): 291,956 接收字節數(字節): 1,753,876 發送字節平均速率(字節/秒): 973.19 接收字節平均速率(字節/秒): 5,846.25 連接錯誤數: 發送錯誤數: 接收錯誤數: 超時錯誤數: 響應代碼 Response Code: 200 - 請求已成功完成。 計數: 1,124 百分比(%): 100.00
| | Normal DataSet | Typed DataSet | 隱藏結果 | ? |
小結 現在,你應該對Typed DataSet有一點了解了,您也明白了它的優勢所在,剩下的就是您在架構程序時的決策了。 有些朋友認為沒有必要使用Typed DataSet,因為帶來了更復雜的結構和更多的代碼,也有一些朋友認為Typed DataSet的性能更差或者沒有改善。這里想說的就是:性能在某些環境下無關緊要,而且另一些環境下卻是產品的最重要特性。過早的優化是一切問題的根源。但是,不重視效率也會導致同樣的結果。您是專業人士,是藝術家,是能工巧將。那么,您一定要知道事物的開銷。如果您不知道或即使您認為自己知道,也要經常進行測量。 參考資料 J.D. Meier, Srinath Vasireddy, Ashish Babbar, and Alex Mackman, Improving .NET Application Performance and Scalability,MSDN HOW TO: Create and Use a Typed DataSet by Using Visual C# .NET, MSDN |