紧凑型框架 SqlDataReader 与 SqlDataAdapter
Compact-Framework SqlDataReader vs SqlDataAdapter
我正在开发一款适用于手持扫描仪设备的旧应用程序 运行 SQL Server CE 和 .Net 3.5。
我的问题与使用 SqlCeDataReader
与 SqlCeDataAdapter
之间的性能有关。我读过很多文章,指出 DataReader
比 DataAdapter
快得多,因为它的开销要少得多,并且一次直接记录一条记录,而不是将 "Fill" 批量写入数据 table 或数据集。
现有的应用程序使用 DataAdapter
,而我正在尝试进行改型以实现 DataReader
,但发现手持设备上的 DataReader
速度较慢,这完全令人困惑我.
总而言之,这是一个简化版本,因为其他帖子也有类似的内容
创建 table...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 )
在此之后,我有一个class,其最基本的格式是
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();
}
并尝试防止反射开销,我正在尝试将数据 reader 直接用于类型化 class.
的属性中
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();
}
该过程实际上执行了 table 的所有 45 个字段,并且两种方法之间的性能几乎相同,在 9 秒内读取 100 条记录,每次都单独查询一个 ID。 Typed 格式使用的表观内存小于 DataTable/DataAdapter,这也令人困惑,因为 Typed 仅存储值的一个实例,但 DataTable 结果在行级别具有整个 ItemArray,并且具有当前值、默认值和原始值的 DataRowVersion。
这没有任何意义,希望有人能为我阐明这一点。
注意:如果我在台式机上做完全相同的事情(针对不同的数据库,但连接、查询等分别相同),typed-class 方法大约是 6 次比数据适配器方法更快。
根据我的经验,使用 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() 根据我的经验,速度确实非常快。缺点是您只能按列顺序获取值,没有列类型或列名。
也不错-微软SQL Server Compact Edition Ultimate Performance Tuning:
我正在开发一款适用于手持扫描仪设备的旧应用程序 运行 SQL Server CE 和 .Net 3.5。
我的问题与使用 SqlCeDataReader
与 SqlCeDataAdapter
之间的性能有关。我读过很多文章,指出 DataReader
比 DataAdapter
快得多,因为它的开销要少得多,并且一次直接记录一条记录,而不是将 "Fill" 批量写入数据 table 或数据集。
现有的应用程序使用 DataAdapter
,而我正在尝试进行改型以实现 DataReader
,但发现手持设备上的 DataReader
速度较慢,这完全令人困惑我.
总而言之,这是一个简化版本,因为其他帖子也有类似的内容
创建 table...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 )
在此之后,我有一个class,其最基本的格式是
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();
}
并尝试防止反射开销,我正在尝试将数据 reader 直接用于类型化 class.
的属性中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();
}
该过程实际上执行了 table 的所有 45 个字段,并且两种方法之间的性能几乎相同,在 9 秒内读取 100 条记录,每次都单独查询一个 ID。 Typed 格式使用的表观内存小于 DataTable/DataAdapter,这也令人困惑,因为 Typed 仅存储值的一个实例,但 DataTable 结果在行级别具有整个 ItemArray,并且具有当前值、默认值和原始值的 DataRowVersion。
这没有任何意义,希望有人能为我阐明这一点。
注意:如果我在台式机上做完全相同的事情(针对不同的数据库,但连接、查询等分别相同),typed-class 方法大约是 6 次比数据适配器方法更快。
根据我的经验,使用 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() 根据我的经验,速度确实非常快。缺点是您只能按列顺序获取值,没有列类型或列名。
也不错-微软SQL Server Compact Edition Ultimate Performance Tuning: