Entity Framework使用反射技术,会影响性能吗?

7

我最终有两个问题与Entity Framework相关,但让我先简单介绍一下背景,这样你就知道我为什么要问这些信息。

在我的工作场所,我的团队计划完全重写我们的应用程序结构,以便我们遵循更现代的标准。这个重新编写包括一个全新的数据层项目。在这个项目中,大多数团队想使用Entity Framework。我也想使用它,因为我非常熟悉它,因为我在个人项目中使用过它。然而,其中一名团队成员强烈反对,声称Entity Framework使用反射并且会影响性能。他的另一个论点是EF使用生成的SQL比存储过程效率低得多。我不太熟悉EF的内部工作方式,我的搜索也没有找到什么极其有用的东西。

以下是我的问题。我尽可能地让它们具体化。如果您需要一些澄清,请问。

问题1 - 反射

  1. EF使用反射并影响性能是否属实?
  2. 如果是,EF在哪里使用反射?
  3. 是否有任何比较性能的资源?我可以使用它来客观地比较.NET数据访问技术,然后将其呈现给我的团队吗?

问题2 - SQL

  1. 这有什么影响?
  2. 是否可以使用存储过程来填充EF实体?
  3. 同样,是否有一些比较生成的查询与存储过程的资源,以及使用存储过程填充实体(如果可以)的影响是什么?

我自己做了一些搜索,但并没有找到太多关于EF底层的东西。

7个回答

9
是的,它像许多其他ORM(NHibernate)和有用的框架(DI工具)一样。例如,WPF没有反射就无法工作。
虽然使用反射的性能影响在过去10年中没有太大改变,自从.NET 1.0以来(尽管有所改进),但随着更快的硬件和对可读性的普遍趋势,现在这已经不再是一个问题。
请记住,主要的性能损失发生在反射绑定时,即将类型元数据读入xxxInfo(如MethodInfo)并在应用程序启动时发生。
调用反射方法肯定会慢一些,但不被认为是一个大问题。

更新

我使用Reflector查看了EF的源代码,并且可以确认它大量使用反射


现在看,这与之前的答案相矛盾。你有一些资源可以提供给我吗? - Chev
好的,我会更新我的答案。让我找到它执行代码的位置。 - Aliostad
请查看我的更新。是的,它进行了大量反射,就像我想象的那样。 - Aliostad

5

问题1的答案:

您可以查看生成的Foo.Designer.cs文件,以了解EF输出的内容。您会发现,生成的容器并没有使用反射,但是确实大量使用了泛型。

以下是Entity Framework肯定使用反射的地方:

  1. 在创建SQL语句时使用Expression<T>接口。 System.Linq中的扩展方法基于表达式树的思想,该树使用System.Reflection中的类型来表示函数调用和类型等。
  2. 当您使用存储过程时,例如:db.ExecuteStoreQuery<TEntity>("GetWorkOrderList @p0, @p1", ...),Entity Framework必须填充实体,并且至少必须检查提供的TEntity类型是否被跟踪。

问题2的答案:

虽然查询经常看起来很奇怪,但这并不意味着它效率低下。您很难想出一个查询的实际查询计划更差。

此外,您确实可以使用存储过程,甚至可以使用实体框架进行内联SQL,用于查询和创建、更新和删除。


附带说明:

即使它在所有地方都使用反射,并且不允许您使用存储过程,那为什么不能使用呢?我认为您需要让您的同事证明这一点。


你知道一些好的资源可以提供这些信息吗?我确实检查了生成的CS文件,但是我并不完全熟悉它们,我只是想知道它是否在其他地方使用。我需要一些硬性事实来支撑我的演示文稿,这样他就无法争辩了。 - Chev
@Chevex:我不是律师,但我认为你可以使用.NET Reflector来检查System.Data.Entity中的源代码,这样应该是安全的。 - John Gietzen
嗯,我会再研究一下。我只希望这些研究已经在网上有了结果:P - Chev
关于你的旁白:不幸的是,我必须证明这将对我们有益而不会伤害我们。由于某种原因,管理层比他们应该受到的更尊重他自负的观点。 - Chev

4

关于生成的EF查询比存储过程效率低这个问题,我可以发表评论。

基本上,有时生成的查询可能会混乱不堪,需要进行一些调整。有许多工具可以帮助您纠正这个问题,例如SQL Profiler、LinqPad等。但是最终生成的查询可能看起来很糟糕,但它们通常运行速度很快。

是的,您可以将EF实体映射到存储过程中。这是可能的,并且将允许您控制一些糟糕的生成EF查询。反过来,您还可以将视图映射到实体,从而控制视图如何选择数据。

我无法想到任何资源,但我必须说一下。使用EF与使用SQL存储过程进行比较是不恰当的。EF提供了一种将数据库直接映射到代码的强大方法。结合LINQ to Entity查询,将使您的开发人员能够快速生成代码。EF是ORM,而SQL存储过程则不是。


+1,好答案。我并不是在将EF与存储过程进行比较,而是将EF生成的SQL与存储过程进行比较。因此,我认为这是一个有效的比较。 - Chev

2
实体框架可能使用反射,但我不认为这会影响性能。基于反射的高端库通常使用轻量级代码生成来缓解成本。它们仅检查每个类型一次以生成代码,然后从那时起使用生成的代码。应用程序启动时会付出一点代价,但从那时起成本可以忽略不计。
至于存储过程,它们比普通查询更快,但这种好处经常被夸大。主要优点是数据库将预编译和存储每个存储过程的执行计划。但是,数据库也会缓存其为普通 SQL 查询创建的执行计划。因此,这种好处取决于应用程序执行的查询数量和类型。如果需要,您可以在实体框架中使用存储过程。

1

我不知道EF是否使用反射(我不认为它会...我想不出需要在运行时确定的信息);但即使它这样做了,又怎么样?

在.NET中到处都使用反射(例如序列化程序),其中一些被频繁调用。

反射并不是非常缓慢;特别是在本文讨论的上下文中。我想制作数据库调用、运行查询、返回查询结果和填充对象的开销肯定比反射的性能开销要大得多。


编辑

Rick Strahl关于反射性能的文章:.Net Reflection and Performance(虽然有点旧,但仍然相关)。


这个人坚信反射是可怕的。你有没有一些资源链接可以用在向团队做演示时使用?我需要一些硬性事实来反驳他的轶事主张。 - Chev
如果我们正在使用WPF或者他真的喜欢WPF,那就可以工作:P - Chev

1

Entity Framework生成的SQL查询语句很好,即使它们不完全符合您的DBA手写的方式。

然而,当涉及到基本类型的查询时,它会生成完全无用的内容。如果您计划使用表格继承方案,并且预计在基本类型上进行查询,则建议谨慎操作。

有关这种奇怪缺陷的更详细解释,请参见我的问题here。请特别注意该问题的已接受答案---这可能是一个错误。

至于反射的问题--我认为您的同事是在无中生有。反射极不可能成为应用程序性能问题的根本原因。


关于反射,我完全同意你的观点。我会查看你提供的链接中的问题。+1 - Chev

0

EF使用反射。我没有检查过,但我认为这是从数据库记录实例化实体的映射的主要点。您将说出列的名称和属性的名称,当数据读取器被执行时,您必须以某种方式填充仅通过其名称知道的属性。

我相信所有这些“性能类似”的问题都通过缓存所需的映射信息正确解决了。由反射引起的性能影响可能与与服务器的网络通信、执行复杂查询等相比微不足道。

如果我们谈论EF的性能,请查看这两个文档:第1部分第2部分。它描述了人们有时认为EF非常慢的一些原因。

存储过程比EF查询更快吗?我的答案是:我认为不是。 Linq的主要优点在于您可以在应用程序中构建查询。当您需要类似列表过滤、分页和排序+更改显示列数、加载相关实体等任何功能时,这非常方便。如果您想在存储过程中实现此功能,则必须针对不同的查询配置使用数十个存储过程或使用动态SQL。动态SQL正是EF所使用的。但在EF的情况下,该查询具有编译时验证,而纯SQL则不然。性能上唯一的差异在于将整个查询发送到服务器时传输数据的数量与仅发送exec procedure和参数时传输数据的数量。

确实有时候查询很奇怪。特别是继承有时会产生糟糕的查询。但这已得到解决。您始终可以使用自定义存储过程或SQL查询返回实体、复杂类型或自定义类型。 EF将为您实现结果,因此您无需担心数据读取器等问题。

如果你想客观地介绍 Entity Framework,那么也应该提到它的缺点。Entity Framework 不支持命令批处理。如果你需要更新或插入多个实体,每个 SQL 命令都会与数据库进行一次来回,因此不应将 EF 用于数据迁移等操作。另一个问题是 EF 几乎没有可扩展性的钩子。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接