对于DataSet,DataReader,sql语句取数据,存储过程取数据这些常见的方式,它们之间的效率问题,网上的评论非常多,而且又不是十分地统一,为了证明它们到底"有多快",我进行了如下测试:
测试一:
主题:DataSet VS DataReader
数据量:10万数据的测试表
连接方式:本机
先进行数据表DataTable的装载测试:
DataTable+sql语句装载
1
SqlConnection conn
=
new
SqlConnection(
"
server=.;database=Test;uid=Test;pwd=test;
"
);
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
然后,我们把这个语句放进存储过程,再测试速度:
存储过程中语句也就是刚刚的查询语句:
DataTable+存储过程装载
1
SqlConnection conn
=
new
SqlConnection(
"
server=.;database=Test;uid=Test;pwd=test;
"
);
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呢,情况会不会有所改变呢?
带着这个问题,我有了如下测试:
DataReader不装进DataTable
1
SqlConnection conn
=
new
SqlConnection(
"
server=.;database=Test;uid=Test;pwd=test;
"
);
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<>对象中,效率究竟怎么样?
List<>装载
1
SqlConnection conn
=
new
SqlConnection(
"
server=.;database=Test;uid=Test;pwd=test;
"
);
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环境下测试延迟加载,看看情况会有什么不同.