为什么 C# Ado.net 比 Entity Framework 6.1.3 慢?
Why is C# Ado.net slower than Entity Framework 6.1.3?
我写了一些代码来比较 C# Ado.Net 和 Entity Framework 6.1.3 的性能。我正在调用一个存储过程,其中 returns 大约 20,000 条员工记录,然后将此数据映射到 "Person" 对象的列表中。然后我 运行 1000 次迭代此代码并计算平均时间。
时间安排如下:
Ado 网络:638 毫秒
Entity Framework:544 毫秒
令我惊讶的是,Ado Net 比 Entity Framework 慢了大约 100 毫秒。
Ado.Net代码:
//GetAllPersons is a stored proc hosted in Local DB instance
var adapter = new SqlDataAdapter("GetAllPersons", conn);
adapter.Fill(dt);
//Using Fast member library
var accessor = TypeAccessor.Create(typeof(Person));
MemberSet members = accessor.GetMembers();
var list = new List<Person>();
foreach(DataRow row in dt.Rows)
{
var person = new Person();
foreach (var member in members)
{
if (row[member.Name] != DBNull.Value)
{
accessor[person, member.Name] = row[member.Name];
}
}
list.Add(person);
}
Entity Framework:
var context = new AdventureWorks2012Entities1();
List<Person> list = context.GetAllPersons().ToList();
使用SQL Adatper 加载Datatable 的代码部分是占用时间最多的部分。我尝试改用 SQL Datareader,但情况更糟。我是否在这里遗漏了什么,因为据说普通 Ado.Net 应该比 Entity Framework 快?
您写道,您尝试过 SqlDataReader,但速度更慢。它应该是最快的,但由于您没有显示您的代码,我们无法提供建议。但这里有一些通用提示:
1.按序号而不是名称获取列值。
与其使用 reader["column_name"]
,不如获取列序号,然后使用它。例如:
using (var reader = command.ExecuteReader())
{
int col1Ordinal = reader.GetOrdinal("Column1");
int col2Ordinal = reader.GetOrdinal("Column2");
while (reader.Read())
{
int col1 = (int)reader[col1Ordinal];
string col2 = (string)reader[col2Ordinal];
// do something with col1 and col2's values
}
}
2。避免多次获取
索引运算符是一个方法调用,因此请避免对同一个值执行多次。在您编写的 SqlDataAdapter 代码中
if (row[member.Name] != DBNull.Value)
{
accessor[person, member.Name] = row[member.Name];
}
如您所见,您调用了 row[member.Name]
两次。相反,您应该获取一次并重新使用值
object value = row[member.Name];
if (value != DBNull.Value)
{
accessor[person, member.Name] = value;
}
3。避免反射
我以前从未听说过 TypeAccessor
或 MemberSet
。从快速搜索来看,它似乎来自一个名为 fast-member
的图书馆。即使它比 .NET 的内置反射快,我也怀疑它有多快。我知道它可以显着减少您必须编写的代码量,这很好,尤其是当您的查询有很多列时。但是,如果您正在尝试优化性能,特别是如果您对与 Entity Framework 相比的代码性能不满意,则应删除该依赖项并测试性能差异。
Entity Framework (EF) 基于Ado.Net;参见 What is Entity Framework? by the Entity Framework Tutorial。因此,EF 不能比纯 Ado.Net 实现更快。
但是,您实现了一个不太理想的解决方案,其中包含循环中的循环和其他开销(例如使用反射)。我想内部 EF 实现比这更聪明,并且可能利用上下文初始化而不是内部循环。
试试这个:在您的 table 中只有一名员工并比较结果。 EF 可能会更慢。
我写了一些代码来比较 C# Ado.Net 和 Entity Framework 6.1.3 的性能。我正在调用一个存储过程,其中 returns 大约 20,000 条员工记录,然后将此数据映射到 "Person" 对象的列表中。然后我 运行 1000 次迭代此代码并计算平均时间。
时间安排如下:
Ado 网络:638 毫秒
Entity Framework:544 毫秒
令我惊讶的是,Ado Net 比 Entity Framework 慢了大约 100 毫秒。
Ado.Net代码:
//GetAllPersons is a stored proc hosted in Local DB instance
var adapter = new SqlDataAdapter("GetAllPersons", conn);
adapter.Fill(dt);
//Using Fast member library
var accessor = TypeAccessor.Create(typeof(Person));
MemberSet members = accessor.GetMembers();
var list = new List<Person>();
foreach(DataRow row in dt.Rows)
{
var person = new Person();
foreach (var member in members)
{
if (row[member.Name] != DBNull.Value)
{
accessor[person, member.Name] = row[member.Name];
}
}
list.Add(person);
}
Entity Framework:
var context = new AdventureWorks2012Entities1();
List<Person> list = context.GetAllPersons().ToList();
使用SQL Adatper 加载Datatable 的代码部分是占用时间最多的部分。我尝试改用 SQL Datareader,但情况更糟。我是否在这里遗漏了什么,因为据说普通 Ado.Net 应该比 Entity Framework 快?
您写道,您尝试过 SqlDataReader,但速度更慢。它应该是最快的,但由于您没有显示您的代码,我们无法提供建议。但这里有一些通用提示:
1.按序号而不是名称获取列值。
与其使用 reader["column_name"]
,不如获取列序号,然后使用它。例如:
using (var reader = command.ExecuteReader())
{
int col1Ordinal = reader.GetOrdinal("Column1");
int col2Ordinal = reader.GetOrdinal("Column2");
while (reader.Read())
{
int col1 = (int)reader[col1Ordinal];
string col2 = (string)reader[col2Ordinal];
// do something with col1 and col2's values
}
}
2。避免多次获取
索引运算符是一个方法调用,因此请避免对同一个值执行多次。在您编写的 SqlDataAdapter 代码中
if (row[member.Name] != DBNull.Value)
{
accessor[person, member.Name] = row[member.Name];
}
如您所见,您调用了 row[member.Name]
两次。相反,您应该获取一次并重新使用值
object value = row[member.Name];
if (value != DBNull.Value)
{
accessor[person, member.Name] = value;
}
3。避免反射
我以前从未听说过 TypeAccessor
或 MemberSet
。从快速搜索来看,它似乎来自一个名为 fast-member
的图书馆。即使它比 .NET 的内置反射快,我也怀疑它有多快。我知道它可以显着减少您必须编写的代码量,这很好,尤其是当您的查询有很多列时。但是,如果您正在尝试优化性能,特别是如果您对与 Entity Framework 相比的代码性能不满意,则应删除该依赖项并测试性能差异。
Entity Framework (EF) 基于Ado.Net;参见 What is Entity Framework? by the Entity Framework Tutorial。因此,EF 不能比纯 Ado.Net 实现更快。
但是,您实现了一个不太理想的解决方案,其中包含循环中的循环和其他开销(例如使用反射)。我想内部 EF 实现比这更聪明,并且可能利用上下文初始化而不是内部循环。
试试这个:在您的 table 中只有一名员工并比较结果。 EF 可能会更慢。