我正在开发一款适用于运行SQL Server CE和.Net 3.5的手持扫描仪设备的旧应用。
我的问题与使用SqlCeDataReader
与SqlCeDataAdapter
之间的效果相关联。我已经阅读了很多说明DataReader
比DataAdapter
快得多,因为它的开销要少得多,并且一次只能直接记录一条记录而不是批量“填充”到数据表或DataSet中。
现有的应用程序使用DataAdapter
,而我正在努力改进实施DataReader
,但在手持设备上找到DataReader
则是SLOWER,这让我很困惑。
总之,这是一个简化版本,因为其他帖子同样具有
创建表格... 45个字段,而不仅仅是3或4个字段样本
// Showing more fields just to show variety of columns of not just
// strings, but of other types too
CREATE TABLE MyTest
(
MyTestID int IDENTITY(1,1) CONSTRAINT MyTestID PRIMARY KEY,
Fld1 int,
Fld2 int,
... (more, just stripped for sample)
fld6 float,
Fld7 nchar(2),
Fld8 float,
Fld9 nchar(2),
Fld10 int,
... (more, just stripped for sample)
Fld24 DATETIME,
Fld25 nchar(1),
Fld26 nchar(15),
Fld27 nvarchar(15),
... (more, just stripped for sample)
Fld44 DATETIME,
Fld45 int )
在此之后,我有一个最基本格式的课程是
public class CTypedClass1
{
public int Fld1 { get; set; }
public int Fld2 { get; set; }
... etc..
public double Fld6 { get; set; }
public double Fld7 { get; set; }
public string Fld8 { get; set; }
... etc to field 45
}
然后我有两个循环计数100个记录的方法,这些记录对应调用数据适配器和DataReader查询的方法
private void ReadMyTestByAdapter()
{
var cmd = MyConnection.GetSQLDbCommand( "Select * from MyTest where MyTestID = @nMyTestParm" );
cmd.Parameters.Add( "nMyTestParm", 1 );
var da = MyConnection.GetSQLDataAdapter();
da.SelectCommand = cmd;
for (int i = 1; i < 100; i++)
{
DataTable tmpTbl = new DataTable();
da.SelectCommand.Parameters[0].Value = i;
QueryByDataAdapter(da, tmpTbl);
}
}
private void ReadMyTestByTypedClass()
{
var cmd = MyConnection.GetSQLDbCommand("Select * from MyTest where MyTestID = @nMyTestParm");
cmd.Parameters.Add("nMyTestParm", 1);
for (int i = 1; i < 100; i++)
{
CTypedClass1 tmpRec = new CTypedClass1();
cmd.Parameters[0].Value = i;
QueryByStruct(cmd, tmpRec);
}
}
现在,通过数据适配器进行查询并将结果填充到DataTable
中private void QueryByDataAdapter(SqlCeDataAdapter da, DataTable putInHere )
{
if (da.SelectCommand.Connection.State != ConnectionState.Open)
da.SelectCommand.Connection.Open();
da.Fill(putInHere);
if (da.SelectCommand.Connection.State == ConnectionState.Open)
da.SelectCommand.Connection.Close();
}
为了尝试防止反射开销,我尝试将数据读取器直接用于类型化类的属性。
private void QueryByStruct(SqlCeCommand cmd, CTypedClass1 curRec)
{
if (cmd.Connection.State != ConnectionState.Open)
cmd.Connection.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
curRec.Fld1 = (int)reader["Fld1"];
curRec.Fld2 = (int)reader["Fld2"];
// etc with rest of fields to 45
// all explicitly (typecast) referenced
}
}
if (cmd.Connection.State == ConnectionState.Open)
cmd.Connection.Close();
}
该过程实际上完成了表的所有45个字段,并且两个方法之间的性能在9秒内几乎完全相同,可以读取100条记录,所有记录一次单独查询一个ID。 Typed格式使用的表观内存小于DataTable / DataAdapter的表观内存,因为Typed只存储值的一个实例,但DataTable结果在行级别具有整个ItemArray,并且具有DataRowVersion,这也是令人困惑的。对于当前值,默认值和原始值。
这没有任何意义,希望有人可以为我揭开这一点。
注意:如果我在台式机上做同样的事情(针对不同的数据库,但分别是连接,查询等),typed-class方法比数据适配器方法快6倍
答案 0 :(得分:1)
根据我的经验使用reader[string]
很慢。当我在HandHeld扫描仪上开发CE时,我使用了以下内容:(不要使用DataAdapter,它更慢)
private void QueryByStruct(SqlCeCommand cmd, CTypedClass1 curRec)
{
if (cmd.Connection.State != ConnectionState.Open)
cmd.Connection.Open();
List<object> fields;
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
var values = new Object[reader.FieldCount];
reader.GetValues(values);
fields = values.ToList();
}
}
if (cmd.Connection.State == ConnectionState.Open)
cmd.Connection.Close();
curRec.Fld1 = (int)fields.ElementAt(1);
curRec.Fld2 = (int)fields.ElementAt(2);
// etc with rest of fields to 45
// all explicitly (typecast) referenced
}
我已将while
更改为if
,因为看起来您只是因为没有正当理由而覆盖了值。根据我的经验GetValues()真的非常快。不利的一面是,您只能按列顺序获取没有列类型和列名称的值。
同样不错 - Microsoft SQL Server Compact Edition终极性能调优: