ADO.NET 中 DataReader 各种读取方式性能比较/测试
来源:互联网 发布:js 数组 concat 编辑:程序博客网 时间:2024/05/22 04:48
刚才看到 http://community.csdn.net/Expert/TopicView3.asp?id=5696773 中关于 box/unbox 问题,以及前几天有朋友问,(<<Type>>)DataReader[<<ColumnIndex>>] 比 Convert.ToXXX(DataReader[<<ColumnName>>]) 的差别,就整理了一下,与大家分享,希望对 .NET 新手而又喜欢嘀咕:“为什么你的程序就是跑得比我快”的朋友有帮助
限于篇,此篇不讨论各种读取方式适用场景了,诸位大虾楼下拍砖吧A.测试结论
非官方,俺自己总结的(以下序号越大,性能越低)
2. DataReader.GetXXX(Dictionary<string, int>[<<ColumnName>>])
[Dictionary<string, int>.Add(<<ColumnName>>, DataReader.GetOrdinal(<<ColumnName>>))]
3. DataReader.GetXXX((Int32)Hashtable[<<ColumnName>>])
[Hashtable.Add(<<ColumnName>>, DataReader.GetOrdinal(<<ColumnName>>))]
4. (<<Type>>)DataReader[<<ColumnIndex>>]
5. DataReader.GetXXX(DataReader.GetOrdinal(<<ColumnName>>))
6. Convert.ToXXX(DataReader[<<ColumnIndex>>])
7. (<<Type>>)DataReader[<<ColumnName>>]
8. Convert.ToXXX(DataReader[<<ColumnName>>]
说明:
1. 按 Index(SELECT 子句中列索引) 读取比按 Name(列名)读取快
2. DataReader.GetXXX(<<ColumnIndex>>) 遥遥领先,基于两点:
a. 此方法内部直接访问对应的数据库类型,不存在 box/unbox 。
b. 基于索引访问。
3. (<<Type>>)DataReader[<<ColumnIndex>>] 比 Convert.ToXXX(DataReader[<<ColumnIndex>>]) 快
a. 前者属于编程语言特有的强制类型转换,对于值类型,存在 unbox 过程。
b. 后者使用的是.NET FCL提供的一组与语言无关的类型转换方法。静态类 Convert 中的类型转换方法,调用源类型实现的 IConvertible 接口进行目标类型的转换。也就是说,只有实现了 IConvertible 接口接口的类型才能用 Convert.ToXXX 进行类型转换。如, Convert.ToInt32(object)
{
if (value != null)
{
return ((IConvertible) value).ToInt32(null);
}
return 0;
}
4. 由于使用 Index 方式访问,容易出错,可维护性差,一种折中方式,是先根据 Name 读取 Index,然后调用 GetXXX 方法。如,
5. 当循环读取所有行时,直接使用方式 4 ,每此都要读取列名(DataReader.GetOrdinal 内部也是一个 Lookup 的过程),因此需要改进。考虑首次读取后将 Name 缓存起来,以后直接读缓存,由于需要 index/name 成对关联,考虑性能,Hashtable 是不二选择,NET 2.0 还提供了泛型版本 System.Collections.Generic.Dictionary<TK,TV> 。
对于非泛型的 Hashtable 只有一个 key 存在 box/unbox,两者性能差别,并不十分明显。
但相对于,各种按 Name 访问方式,有明显的性能优势。
6. 以上各组读取方式比较,随着数据量的增加,性能差异越来越明显,少量数据读取无法看出明显差别。
7. 对于借助于自动化工具、代码生成工具开发应用程序,应该优先考虑 GetXXX 的方式读取。
8. xxxDataAdapter.Fill 方法内部使用对应 Data Provider 的 xxxDataReader 填充 DataTable。
B.测试实例
说明
1. 此测试,直接使用 ASP.NET(似乎不影响对比性),抱歉了,偶就会 WebForm,比较理想的当然整个 Console Applilcation 让她跑
2. 懒于准备样表数据,直接使用 SQL Server 2k. Northwind.Products 表,且只读取 ProductID 字段(INT 型),并由应用程序多次重复读取同一数据,模拟大数据量的效果
3. 测试结果为,用 SqlDataReader 分别读取
5,000
50,000
500,000
5,000,000
50,000,000
条记录(模拟)所花的总时间,单位为秒,
这里显示了连续 5 次的测试结果。
测试代码
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Import Namespace="System.IO" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void Button1_Click(object sender, EventArgs e)
...{
int i = 5;
while (i-- > 0) ...{
ExecuteTest();
System.Threading.Thread.Sleep(1000 * 10);
}
}
private void ExecuteTest()
...{
const int COLUMN_INDEX_PRODUCT_ID = 0;
const string COLUMN_NAME_PRODUCT_ID = "ProductID";
StringBuilder sb = new StringBuilder();
int loops = 100;
for (int k = 0; k < 5; k++, loops *= 10) ...{
sb.AppendFormat("{0, 10:N0} ", loops * 50);
// 1. DataReader.GetXXX(<<ColumnIndex>>)
using (SqlDataReader dr = GetDataReader()) ...{
int productId, i;
DateTime start = DateTime.Now;
while (dr.Read()) ...{
i = loops;
while (i-- > 0) ...{
productId = dr.GetInt32(COLUMN_INDEX_PRODUCT_ID);
}
}
DateTime end = DateTime.Now;
TimeSpan span = end - start;
sb.Append(span.TotalSeconds.ToString("f7")).Append(" ");
}
// 2. (<<Type>>)DataReader[<<ColumnIndex>>]
using (SqlDataReader dr = GetDataReader()) ...{
int productId, i;
DateTime start = DateTime.Now;
while (dr.Read()) ...{
i = loops;
while (i-- > 0) ...{
productId = (int)dr[COLUMN_INDEX_PRODUCT_ID];
}
}
DateTime end = DateTime.Now;
TimeSpan span = end - start;
sb.Append(span.TotalSeconds.ToString("f7")).Append(" ");
}
// 3. Convert.ToXXX(DataReader[<<ColumnIndex>>])
using (SqlDataReader dr = GetDataReader()) ...{
int productId, i;
DateTime start = DateTime.Now;
while (dr.Read()) ...{
i = loops;
while (i-- > 0) ...{
productId = Convert.ToInt32(dr[0]);
}
}
DateTime end = DateTime.Now;
TimeSpan span = end - start;
sb.Append(span.TotalSeconds.ToString("f7")).Append(" ");
}
// 4. (<<Type>>)DataReader[<<ColumnName>>]
using (SqlDataReader dr = GetDataReader()) ...{
int productId, i;
DateTime start = DateTime.Now;
while (dr.Read()) ...{
i = loops;
while (i-- > 0) ...{
productId = (int)dr[COLUMN_NAME_PRODUCT_ID];
}
}
DateTime end = DateTime.Now;
TimeSpan span = end - start;
sb.Append(span.TotalSeconds.ToString("f7")).Append(" ");
}
// 5. Convert.ToXXX(DataReader[<<ColumnName>>]
using (SqlDataReader dr = GetDataReader()) ...{
int productId, i;
DateTime start = DateTime.Now;
while (dr.Read()) ...{
i = loops;
while (i-- > 0) ...{
productId = Convert.ToInt32(dr[COLUMN_NAME_PRODUCT_ID]);
}
}
DateTime end = DateTime.Now;
TimeSpan span = end - start;
sb.Append(span.TotalSeconds.ToString("f7")).Append(" ");
}
// 6. DataReader.GetXXX(DataReader.GetOrdinal(<<ColumnName>>))
using (SqlDataReader dr = GetDataReader()) ...{
int productId, i;
DateTime start = DateTime.Now;
while (dr.Read()) ...{
i = loops;
while (i-- > 0) ...{
productId = dr.GetInt32(dr.GetOrdinal(COLUMN_NAME_PRODUCT_ID));
}
}
DateTime end = DateTime.Now;
TimeSpan span = end - start;
sb.Append(span.TotalSeconds.ToString("f7")).Append(" ");
}
// 7. DataReader.GetXXX((Int32)Hashtable[<<ColumnName>>])
// Hashtable.Add(<<ColumnName>>, DataReader.GetOrdinal(<<ColumnName>>))
using (SqlDataReader dr = GetDataReader()) ...{
int productId, i;
DateTime start = DateTime.Now;
Hashtable columns = new Hashtable();
int j = 0;
while (dr.Read()) ...{
i = loops;
while (i-- > 0) ...{
if (j++ == 0) columns.Add(COLUMN_NAME_PRODUCT_ID, dr.GetOrdinal("ProductID"));
productId = dr.GetInt32((int)columns[COLUMN_NAME_PRODUCT_ID]);
}
}
DateTime end = DateTime.Now;
TimeSpan span = end - start;
sb.Append(span.TotalSeconds.ToString("f7")).Append(" ");
}
// 8. DataReader.GetXXX(Dictionary<string, int>[<<ColumnName>>])
// Dictionary<string, int>.Add(<<ColumnName>>, DataReader.GetOrdinal(<<ColumnName>>))
using (SqlDataReader dr = GetDataReader()) ...{
int productId, i;
DateTime start = DateTime.Now;
Dictionary<string, int> columns = new Dictionary<string, int>();
int j = 0;
while (dr.Read()) ...{
i = loops;
while (i-- > 0) ...{
if (j++ == 0) columns.Add(COLUMN_NAME_PRODUCT_ID, dr.GetOrdinal("ProductID"));
productId = dr.GetInt32(columns[COLUMN_NAME_PRODUCT_ID]);
}
}
DateTime end = DateTime.Now;
TimeSpan span = end - start;
sb.Append(span.TotalSeconds.ToString("f7")).Append(" ");
}
sb.AppendLine();
}
sb.AppendLine();
string path = Server.MapPath("result.txt");
File.AppendAllText(path, sb.ToString());
}
private SqlDataReader GetDataReader()
...{
string connStr = "server=.;database=Northwind;uid=sa;";
SqlConnection conn = new SqlConnection(connStr);
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "SELECT TOP 50 ProductID FROM Products";
conn.Open();
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Performance Testing when retrieving data with DataReader </title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Run Test" />
</div>
</form>
</body>
</html>
读取方式,从左往右依次是:
2. (<<Type>>)DataReader[<<ColumnIndex>>]
3. Convert.ToXXX(DataReader[<<ColumnIndex>>])
4. (<<Type>>)DataReader[<<ColumnName>>]
5. Convert.ToXXX(DataReader[<<ColumnName>>]
6. DataReader.GetXXX(DataReader.GetOrdinal(<<ColumnName>>))
7. DataReader.GetXXX((Int32)Hashtable[<<ColumnName>>])
[Hashtable.Add(<<ColumnName>>, DataReader.GetOrdinal(<<ColumnName>>))]
8. DataReader.GetXXX(Dictionary<string, int>[<<ColumnName>>])
[Dictionary<string, int>.Add(<<ColumnName>>, DataReader.GetOrdinal(<<ColumnName>>))]
- ADO.NET 中 DataReader 各种读取方式性能比较/测试
- ADO.NET 中 DataReader 各种读取方式性能比较/测试
- ADO.NET 中 DataReader 各种读取方式性能比较/测试
- ADO.NET 中 DataReader 各种读取方式性能差别
- ADO.NET --DataReader对象
- ADO.net之DataReader
- ADO.NET——Command(执行SQL) & DataReader(读取数据库)
- ADO.Net:从DataReader中获取数据表的Schema信息
- ADO.Net:使用DataReader向数据库中插入数据
- ADO.net中的DataReader对象
- ADO.net入门之DataReader
- ADO.NET中的DataReader简介
- Java中读取输入方式的性能比较
- android性能测试中各种数据的获取方式
- c# 中关于DataReader读取数据的方式
- ADO.Net命令执行方式比较
- C# ADO.net DataReader数据库读取GetString得到NULL值的处理
- ADO.net 中数据库连接方式
- 嵌入式C语言笔试题(2)
- 两起跳槽引发的道德思考
- JavaScript学习笔记3
- 面向服务的体系结构SOA简介
- Visual C++ 2008 Feature Pack
- ADO.NET 中 DataReader 各种读取方式性能比较/测试
- sql server 分页
- 软件项目管理(zt)
- MYSQL命令行模式管理
- 最佳ASP.NET编程习惯
- PHP5的Simplexml
- 怎样选择门?
- 内网安全技术十大策略
- 2008-01-18 study php Script