我写了很多的帖子关于orm,今天我还想再说一遍:在关键的高并发的Web应用程序中使用ORM工具,是在过去几年中软件阶级所做的最伟大的愚蠢架构。
WEB应用程序的瓶颈都在服务器的资源;内存和处理器的时间. 这些都是有特别高的成本。
让我们从0开始回顾一下一个http request是如何被处理的:
1.加载和初始化数据库的context,
2.把LINQ表达式编译转换成SQL语句,
3.发射SQL到服务器上 ,server 编译sql, 生成执行计划 ,优化查询,
4. 执行编译后的query,
5.转换结果为无类型的ADO数据集,
6. 生成有类型的ADO数据集,
7.使用反射 这种 最没有效率的方式 生成 实体 实例
8.从实体创建可序列化的对象,
9.创建XML或JSON对象,并将其传递到 output stream。
只有2个步骤是为任务(4和9)中的所有其他必要的 - 垃圾。考虑到EF(V3.5至少)会产生非常低效的查询与很多 子查询,这使得SQL服务器不得不一直工作在效率最低的模式。
建议:
使用LINQ to DataSet中(http://msdn.microsoft.com/en-us/library/bb386977.aspx)作为一种重量轻的工具Web应用程序。
使用LINQ to DataSet 你会得到少得多几乎相同的结果。而且还非常快.几乎是工业应用中最快的解决方案了.
当然, 对于小型数据库小型/个人网站我 使用LINQ to SQL /entity framework/ hibernate ... 或任何其他的ORM我想不是问题。
但是,对于专业网站,性能确实很重要,天下武功,唯快不破.
我学会了永远不要依靠一个ORM。纯粹的ADO,是唯一的答案,没有什么比它的性能更好了。当然这可能需要更长的时间来写DAL,但一旦这样做了,我相信我不会有任何其他的问题。
要知道,所有的ORM都有自己的问题,缺陷,性能问题和解决这些轻松的时间比任何时候我会用写纯SQL更多的时间。
当然,这是假定开发者能够编写DAL,并且有足够的智商来理解sql。 现实很简单,要么和orm一起完蛋,要么拿起了一本书,好好学习SQL。
学习SQL,绝对是个好主意,因为它似乎很多开发员甚至没有基本的SQL知识。你懂,你就赢了.
------解决思路----------------------
大部分同意,但高并发的web应用如果全都是对数据库的直接访问,也一样是愚蠢的吧。真正高并发下所有数据操作都直接对数据库操作,也绝对会有问题。orm带来的好处,通过ADO访问数据库各有各的好处,应该具体应用场景具体分析,不能一概而论吧
------解决思路----------------------
需要的是我们对框架和业务场景的深刻理解,做到有目的的选择技术,而不是盲目的跟随潮流。在对orm框架和sql都有比较深入的理解后才能真正达到提高性能的目的。否则可能手写的sql有时候还没有orm快,或者用orm却不知道它慢在哪里。
在有些应用场景,可能仅仅关掉EF的ChangeTracking就能够满足性能的需要了,如果是这种情况,手写DAL就得不偿失。part-1,part-2是两篇orm查询性能的比较,可以看到对于EF,是否ChangeTracking的巨大差异。如果要用EF,它的性能注意事项,或者中文版(没有更新到EF6)必须要看明白。
当然EF可能会产生低效的sql,在更高的性能要求下,需要手动控制的时候用micro-orm框架会是一个性能和生产力的很好的平衡点,比如Dapper。自己写sql,它帮忙支持参数化查询,和结果的实体映射(或者dynamic方式),效率非常高。关于LZ说的第7步,实际上orm框架都不是用反射来创建实体的,那样的性能不可接受,而是用emit il的方式,它产生的il执行效率不会比手写的慢。
另外还存在一种问题,有些人对性能的追求不是来自业务场景的需要,而是出于自己对系统精确控制的感觉的需要或是为了体现自我价值。把自己关注的一个点的性能提到很重要的位置,却故意忽视了系统的真正瓶颈。这是比单纯的技术选择带来的影响更可怕。
------解决思路----------------------
ORM为了解决程序开发中处理的对象格式与关系数据库的数据零散格式之间的“阻抗不匹配”问题。当然它可以集成一些近些年最新的框架知识,但是它肯定不是单纯地为了得到“最高操作效率”的目的的。你永远都能用低级的手段得到“最高操作效率”。所以没有谁在使用EF的时候禁止你同时使用ADO.NET。
你想到一个sql表达式可能非常复杂的时候,你肯定需要同时使用ADO.NET和EF两个版本来进行研究。而一般来说,新手几乎都会感兴趣于EF,这是你阻挡不了的。这就好像有人强调c语言程序如果写得好的话、永远都比c#程序(可能)运行得更快,然而我们其实都知道c程序员做现代高级语言的程序猿的工作是多么慢、项目缺乏扩展张力。
一个ORM并不需要每一次运行都翻译sql语句,它可以仅仅翻译一次然后就重复使用,甚至可以把上一进程的翻译结果保存到当前磁盘中让下一个进程在启动时先读取。同样地,就算EF是反射的(而实际它是自动生成代码的),那么也仅需要反射一次然后就把内存中生成的操作过程做为委托而重复调用。
我不用EF主要有两个原因。其一是因为它不能直接支持多态,其二是因为以前它不支持CodeFirst模式(现在也不太给力)。不过我认为它一直在改进。只不过我现在不用关系数据库了,一直没有精力去研究其编程的最佳实践、性能陷阱而已。
EF应该提供更多更好的编程实践,来避免一些容易滥用的陷阱。但是对于 .net 程序员而言,应该知道的关于性能的东西很多(例如善用缓存、业务架构设计、前端编程而不是服务器编程,等等),把一切性能问题都归咎到查询数据库的几条代码上,这其实可能是在事业上的一个“没有发展”的表现。
------解决思路----------------------
封装+透明 与 完整 只能是某个人的当前时概念,最多满足你个人的当前需求,既不可能满足他人需求,也不可能满足未来需求。
所有的抽象都应该是需求驱动的,没有需求就没有设计,没有抽象。
那种生硬的private属于过度设计,把门关起来,却留出一扇窗,这种行为与掩耳盗铃没有区别,只不过大多数人都被教条了。