究竟哪种取数据的方式最快?
对于DataSet,DataReader,sql语句取数据,存储过程取数据这些常见的方式,它们之间的效率问题,网上的评论非常多,而且又不是十分地统一,为了证明它们到底"有多快",我进行了如下测试:
测试一:
主题:DataSet VS DataReader
数据量:10万数据的测试表
连接方式:本机
先进行数据表DataTable的装载测试:

2 DataTable resultDt = new DataTable();
3 resultDt.Columns.Add(new DataColumn("Id", typeof(int)));
4 resultDt.Columns.Add(new DataColumn("TestData1",typeof(string)));
5 resultDt.Columns.Add(new DataColumn("TestData2", typeof(string)));
6 string queryStr = "select * from TestTable";//构建数据表,连接对象及查询语句
7 Stopwatch watch1 = new Stopwatch();//方式一:DataSet方式装载
8 watch1.Start();
9 SqlDataAdapter sda = new SqlDataAdapter(queryStr, conn);
10 DataSet ds = new DataSet();
11 sda.Fill(ds);
12 resultDt = ds.Tables[0];
13 watch1.Stop();
14
15
16 Stopwatch watch2 = new Stopwatch();//方式二:DataReader方式装载
17 watch2.Start();
18 SqlCommand cmd = new SqlCommand(queryStr, conn);
19 conn.Open();
20 SqlDataReader sdr = cmd.ExecuteReader();
21 while (sdr.Read()) {
22 DataRow dr = resultDt.NewRow();
23 dr["Id"] = sdr["id"];
24 dr["TestData1"] = sdr["TestData1"];
25 dr["TestData2"] = sdr["TestData2"];
26 resultDt.Rows.Add(dr);
27 }
28 sdr.Close();
29 conn.Close();
30 watch2.Stop();
31
32 Console.WriteLine("DataSet method,Reflection: " + watch1.Elapsed);
33 Console.WriteLine("DataReader method,Reflection: " + watch2.Elapsed);
34 Console.ReadLine();
测试结果:
DataSet method,Reflection: 00:00:01.0080464
DataReader method,Reflection: 00:00:01.1056812
然后,我们把这个语句放进存储过程,再测试速度:
存储过程中语句也就是刚刚的查询语句:

2 DataTable resultDt = new DataTable();
3 resultDt.Columns.Add(new DataColumn("Id", typeof(int)));
4 resultDt.Columns.Add(new DataColumn("TestData1", typeof(string)));
5 resultDt.Columns.Add(new DataColumn("TestData2", typeof(string)));
6
7
8
9 SqlCommand cmd = new SqlCommand();
10 cmd.CommandType = CommandType.StoredProcedure;
11 cmd.CommandText = "GetTestData";
12 cmd.Connection = conn;
13
14 Stopwatch watch1 = new Stopwatch();
15 watch1.Start();
16 SqlDataAdapter sda = new SqlDataAdapter(cmd);
17 DataSet ds = new DataSet();
18 sda.Fill(ds);
19 resultDt = ds.Tables[0];
20 watch1.Stop();
21
22
23 Stopwatch watch2 = new Stopwatch();
24 watch2.Start();
25 conn.Open();
26 SqlDataReader sdr = cmd.ExecuteReader();
27 while (sdr.Read())
28 {
29 DataRow dr = resultDt.NewRow();
30 dr["Id"] = sdr["id"];
31 dr["TestData1"] = sdr["TestData1"];
32 dr["TestData2"] = sdr["TestData2"];
33 resultDt.Rows.Add(dr);
34 }
35 sdr.Close();
36 conn.Close();
37 watch2.Stop();
38
39 Console.WriteLine("DataSet method,Reflection: " + watch1.Elapsed);
40 Console.WriteLine("DataReader method,Reflection: " + watch2.Elapsed);
41 Console.ReadLine();
运行结果为:
DataSet method,Reflection: 00:00:01.0025863
DataReader method,Reflection: 00:00:01.1531541
小结:不管是SQL语句方式,还是存储过程方式,把数据装进DataTable,DataSet方式都比DataReader要快一点点.要是不装载到DataTable呢,情况会不会有所改变呢?
带着这个问题,我有了如下测试:

2 DataTable resultDt = new DataTable();
3 resultDt.Columns.Add(new DataColumn("Id", typeof(int)));
4 resultDt.Columns.Add(new DataColumn("TestData1", typeof(string)));
5 resultDt.Columns.Add(new DataColumn("TestData2", typeof(string)));
6 string queryStr = "select * from TestTable";
7 Stopwatch watch1 = new Stopwatch();
8 watch1.Start();
9 SqlDataAdapter sda = new SqlDataAdapter(queryStr, conn);
10 DataSet ds = new DataSet();
11 sda.Fill(ds);
12 resultDt = ds.Tables[0];
13 watch1.Stop();
14
15
16 Stopwatch watch2 = new Stopwatch();
17 watch2.Start();
18 SqlCommand cmd = new SqlCommand(queryStr, conn);
19 conn.Open();
20 SqlDataReader sdr = cmd.ExecuteReader();
21 int i = 0;
22 while (sdr.Read())
23 {
24 i++;
25 }
26 sdr.Close();
27 conn.Close();
28 watch2.Stop();
29
30 Console.WriteLine("DataSet method,Reflection: " + watch1.Elapsed);
31 Console.WriteLine("DataReader method,Reflection: " + watch2.Elapsed);
32 Console.ReadLine();
33
运行结果:
DataSet method,Reflection: 00:00:00.9876266
DataReader method,Reflection: 00:00:00.1093267
情况有了改变.但现实中,DataReader不装载到任何对象中的情况还是非常少的.例如,我们经常把这些数据装到List<>对象中,效率究竟怎么样?

2 List<TestData> resultDt = new List<TestData>();
3 TestData td = null;
4 string queryStr = "select * from TestTable";
5 Stopwatch watch1 = new Stopwatch();
6 watch1.Start();
7 SqlDataAdapter sda = new SqlDataAdapter(queryStr, conn);
8 DataSet ds = new DataSet();
9 sda.Fill(ds);
10 foreach (DataRow dr in ds.Tables[0].Rows) {
11 td = new TestData();
12 td.Id = Convert.ToInt32(dr["Id"]);
13 td.TestData1 = dr["TestData1"].ToString();
14 td.TestData2 = dr["TestData2"].ToString();
15 resultDt.Add(td);
16 }
17 watch1.Stop();
18
19
20 Stopwatch watch2 = new Stopwatch();
21 watch2.Start();
22 SqlCommand cmd = new SqlCommand(queryStr, conn);
23 conn.Open();
24 SqlDataReader sdr = cmd.ExecuteReader();
25 while (sdr.Read())
26 {
27 td = new TestData();
28 td.Id = Convert.ToInt32(sdr["Id"]);
29 td.TestData1 = sdr["TestData1"].ToString();
30 td.TestData2 = sdr["TestData2"].ToString();
31 resultDt.Add(td);
32 }
33 sdr.Close();
34 conn.Close();
35 watch2.Stop();
36
37 Console.WriteLine("DataSet method,Reflection: " + watch1.Elapsed);
38 Console.WriteLine("DataReader method,Reflection: " + watch2.Elapsed);
39 Console.ReadLine();
运行结果:
DataSet method,Reflection: 00:00:01.1134010
DataReader method,Reflection: 00:00:00.4901601
小结:
DataSet中包含了DataTable的集合,所以,在SqlDataAdapter.Fill(ds)的过程中,其实已经进行了一次数据装载,再装载到其它对象,等于是进行了2次装载.故尔速度稍慢.
要将数据装到DataTable时,DataReader比DataSet要慢,而装载到List<>对象时,DataReader要比DataTable快至少一倍.
我目前用的是2005的测试环境,下次我会到2008环境下测试延迟加载,看看情况会有什么不同.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述