为什么C#Ado.net比实体框架6.1.3慢?

为什么C#Ado.net比实体框架6.1.3慢?,c#,ado.net,entity-framework-6,C#,Ado.net,Entity Framework 6,我编写了一些代码来比较C#Ado.Net和Entity Framework 6.1.3的性能。我正在调用一个存储过程,它返回大约20000条员工记录,然后将这些数据映射到“Person”对象列表中。然后我对这段代码进行了1000次迭代,并计算了平均时间 以下是时间安排: Ado-Net:638ms 实体框架:544 ms 令我惊讶的是,Ado Net比实体框架慢大约100毫秒 Ado.Net代码: //GetAllPersons is a stored proc hosted in

我编写了一些代码来比较C#Ado.Net和Entity Framework 6.1.3的性能。我正在调用一个存储过程,它返回大约20000条员工记录,然后将这些数据映射到“Person”对象列表中。然后我对这段代码进行了1000次迭代,并计算了平均时间

以下是时间安排:

  • Ado-Net:638ms

  • 实体框架:544 ms

令我惊讶的是,Ado Net比实体框架慢大约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);
    }
//GetAllPersons是托管在本地DB实例中的存储过程
var adapter=newsqldataadapter(“GetAllPersons”,conn);
适配器填充(dt);
//使用快速成员库
var accessor=TypeAccessor.Create(typeof(Person));
MemberSet members=accessor.GetMembers();
var list=新列表();
foreach(数据行中的数据行)
{
var person=新的person();
foreach(成员中的var成员)
{
if(行[member.Name]!=DBNull.Value)
{
访问者[个人,成员.名称]=行[成员.名称];
}
}
列表。添加(人);
}
实体框架:

        var context = new AdventureWorks2012Entities1();
        List<Person> list = context.GetAllPersons().ToList();
var context=newAdventureWorks2012Entities1();
List=context.GetAllPersons().ToList();

使用SQL Adatper加载数据表的代码部分占用了大部分时间。我尝试改用SQL Datareader,但效果更糟。我是否遗漏了一些东西,因为假定普通的Ado.Net应该比实体框架更快?

您写道,您尝试了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];
}
如您所见,您正在调用
行[member.Name]
两次。相反,您应该获取一次并重新使用该值

object value = row[member.Name];
if (value != DBNull.Value)
{
  accessor[person, member.Name] = value;
}
3。避免反思

我以前从未听说过
TypeAccessor
MemberSet
。通过快速搜索,它似乎来自一个名为
fast member
的库。即使它比.NET的内置反射更快,我也怀疑它有多快。我知道这很好,因为它可以显著减少您必须编写的代码量,特别是当您的查询有许多列时。但是,如果您试图优化性能,特别是如果您对代码与实体框架相比的性能不满意,则应该删除该依赖项并测试性能差异。

实体框架(EF)基于Ado.Net;看旁边。因此,EF不能比纯Ado.Net实现更快

但是,您使用循环中的循环和其他开销(如使用反射)实现了一个不太理想的解决方案。我认为内部EF实现比这更智能,并且可能使用上下文初始化,而不是使用内部循环


尝试这样做:在您的表中只有一名员工,并比较结果。EF可能较慢。

EF基于Ado.Net,因此它不能比纯Ado.Net实现更快。但是,您实现了一个不太理想的解决方案,其中包含循环中的循环和其他开销。我认为内部EF实现比这更智能,并且可能使用上下文初始化而不是内部循环。实验:表格中只有一名员工并进行比较。
DataAdapter.Fill(DataTable)
非常慢。将代码重写为使用手动映射-速度更快。@QualityCatalyst是的,这很有意义。正如您所建议的,我为一名员工运行了代码,Ado.Net比Entity Framework快50%左右。我一直在增加员工数量,当EF开始接管时,员工数量达到了100人左右。@AlexanderPetrov我希望避免手动映射,因为我正在寻找一个通用的Ado.net代码,用于任何实体。如果希望避免手动映射,请使用ORM(EF、Linq2Sql、Linq2DB、NHibernate等)或micro ORM(Dapper、PetaPoco、Massive)。在使用SQL DataReader时,我在执行reader.Read()时一次向Datatable添加一行因为我想让我的代码适用于可变数量的列/不同的实体。我并没有太多关注多个GET,因为它已经很快了。我已经测试了fast成员库的性能,发现它比一般反射代码快50%左右。在这种情况下,您的基准测试是将苹果和桔子进行比较。两种技术之间的一个有意义的基准必须比较相同的输入和输出,否则你不仅仅是在比较技术,而是在比较不同技术的不同方法。