哪个会更快。
1)循环数据读取器并创建基于自定义行和列的填充数据表
2)或创建一个dataAdapter对象并只是(.Fill)一个数据表。
在动态创建数据表时,数据读取器的性能是否仍然适用?
哪个会更快。
1)循环数据读取器并创建基于自定义行和列的填充数据表
2)或创建一个dataAdapter对象并只是(.Fill)一个数据表。
在动态创建数据表时,数据读取器的性能是否仍然适用?
DataAdapter 在后台使用 DataReader,因此您的体验可能是相同的。
DataAdapter 的好处是您删减了大量需要维护的代码。
这场辩论有点宗教问题,所以一定要环顾四周,决定什么最适合你的情况:
假设您实际上想要从数据库返回所有数据,那么在数据库和网络上花费的时间几乎肯定会使进程内在内存中填充数据结构所花费的时间相形见绌。
是的,在某些情况下,您可能会通过使用 DataReader 节省少量费用 - 特别是如果您想流式传输数据,它可能很有用 - 但如果您确实需要它,我会坚持使用最简单的代码。如果您认为 DataSet 人口正在导致严重的性能问题,请对其进行分析,然后尝试对其进行改进。
您的选项#1会更慢。但是,与手动添加自定义行相比,将数据读取器转换为数据表有更好的方法:
DataTable dt = new DataTable();
using (SqlConnection conn = GetOpenSqlConnection())
using (SqlCommand cmd = new SqlCommand("SQL Query here", conn)
using (IDataReader rdr = cmd.ExecuteReader())
{
dt.Load(rdr);
}
我无法评论 this 和 using 之间的区别.Fill()
。
我不能说填充数据表本身,但使用数据阅读器是最有效的阅读方法。
数据读取器更快。如果您使用的是 2.0+,您可能甚至不必使用数据表。您可以使用对象的通用列表。
当您需要显示加载数据的进度时,使用 DataReader 非常好。在 DataSet 中,您不能在加载数据的过程中做某事。
另一方面,DataSet 是一体式对象。所以 DataSet 慢得多。DataReader 可以在代码中数据操作非常缓慢的地方为您提供额外的提升。在这些地方将其从 DataSet 更改为 DataReader。DataReader 还占用更少的内存空间。
哦,当然,编写好的 DataReader 需要更多时间,但这是值得的。例如,当您播放从数据库中获取的图像或音乐时。
与许多这样的问题一样,答案是:取决于。
如果您事先不知道数据的结构并且正在动态创建 TableAdapter,那么动态 DataTable 会更有效。创建 TableAdapter 涉及大量代码生成。
但是,如果您事先知道数据的结构,那么问题就变成了,我需要多少功能?
如果您需要完整的 CRUD 实现,那么使用 TableAdapter 可以获得一些效率,而不是自己编写所有的 CRUD 代码。此外,TableAdapter 实现还可以(不是很好)。如果您需要更高效的东西,那么使用 nHibernate 或其他一些 ORM 可能会更好。
如果您不需要完整的 CRUD 实现(即这是一个只读解决方案)并且预先知道您的数据结构,那么您必须针对动态生成的 DataTable 测试 TableAdapter 只读实现的效率. 如果我是一个赌徒,我会把钱放在 TableAdapter 实现上,因为您绑定数据一次并多次读取它。
采用DataReader
'sRead
是一种只进、一次一行的方法,它按顺序读取数据,以便在连接时立即读取记录,这将是内存和性能的最佳选择。
也就是说,在这两种方法之间,我发现IDataAdapter.Fill
比DataTable.Load
. 当然,这取决于实现。这是我在此处发布的两者之间的基准:
public DataTable Read1<T>(string query) where T : IDbConnection, new()
{
using (var conn = new T())
{
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = query;
cmd.Connection.ConnectionString = _connectionString;
cmd.Connection.Open();
var table = new DataTable();
table.Load(cmd.ExecuteReader());
return table;
}
}
}
public DataTable Read2<S, T>(string query) where S : IDbConnection, new()
where T : IDbDataAdapter, IDisposable, new()
{
using (var conn = new S())
{
using (var da = new T())
{
using (da.SelectCommand = conn.CreateCommand())
{
da.SelectCommand.CommandText = query;
da.SelectCommand.Connection.ConnectionString = _connectionString;
DataSet ds = new DataSet(); //conn is opened by dataadapter
da.Fill(ds);
return ds.Tables[0];
}
}
}
}
第二种方法总是优于第一种。
Stopwatch sw = Stopwatch.StartNew();
DataTable dt = null;
for (int i = 0; i < 100; i++)
{
dt = Read1<MySqlConnection>(query); // ~9800ms
dt = Read2<MySqlConnection, MySqlDataAdapter>(query); // ~2300ms
dt = Read1<SQLiteConnection>(query); // ~4000ms
dt = Read2<SQLiteConnection, SQLiteDataAdapter>(query); // ~2000ms
dt = Read1<SqlCeConnection>(query); // ~5700ms
dt = Read2<SqlCeConnection, SqlCeDataAdapter>(query); // ~5700ms
dt = Read1<SqlConnection>(query); // ~850ms
dt = Read2<SqlConnection, SqlDataAdapter>(query); // ~600ms
dt = Read1<VistaDBConnection>(query); // ~3900ms
dt = Read2<VistaDBConnection, VistaDBDataAdapter>(query); // ~3700ms
}
sw.Stop();
MessageBox.Show(sw.Elapsed.TotalMilliseconds.ToString());
Read1
看起来更好,但数据适配器性能更好(不要混淆一个数据库优于另一个,查询都是不同的)。两者之间的差异取决于查询。原因可能是在添加行时需要从文档Load
中逐行检查各种约束(它是一种方法),而在 DataAdapters 上是专门为此而设计的 - 快速创建 DataTables。DataTable
Fill
依靠。如果您希望一次获取所有记录,DataAdapter 可以快 2 到 25 倍。当您只需要一列或两列并希望一次更改一个时,数据读取器非常好,但是执行时间如预期的那样很慢。DA 最大的问题是缺乏异步方法——然而,MS 没有计划使 DA 异步。虽然 DA 在后台使用 DR,但它已经被磨练到完美,并且在 C# 中使用 DR 编写自己的循环肯定会更慢。