转载地址 http://www.cnblogs.com/Barton131420/archive/2007/01/07/613955.html
对ORM的认识,大家褒贬不一,但是从这位作者的身上,看到了他对ORM的偏爱,也从他的字里行间体会到了ORM优越之处,与大家共享。
性能
ORM提供了所有SQL语句的生成,代码人员远离了数据库概念。从一个概念需求(例如一个HQL)映射为一个SQL语句,并不需要什么代价,连1%的性能损失都没有。真正的性能损失在映射过程中,更具体地讲,是在对象实例化的过程中。我曾经做过一个试验,以“计算第N个素数”这样的命题。我采用Delphi写Native Win32 Console程序,又采用C#写CLR Console程序。两者相比,令我大失所望。
N | 结果 | 耗时 | |
Delphi | C# | ||
1000 | 7927 | 0ms | 2ms |
10000 | 104743 | 16ms | 17ms |
100000 | 1299721 | 438ms | 324ms |
1000000 | 15485867 | 11437ms | 7823ms |
不知道各位是否已经明白了性能在哪儿损失了:内存分配。Native的内存分配与释放都是非常耗时的操作系统行为。但在托管环境下,内存的释放是GC干的事情,甚至不需要统计到耗时中,而内存的分配也是一件非常快捷的事情。当然,即使是快捷也还是需要耗时的。这让我联想到DataSet的性能。DataSet也是一种数据容器,但是却没有多少人抱怨DataSet的性能。如果你明白DataSet的机制,就会发现,DataStorage巧妙地规避了内存分配和耗时的问题。而我们的ORM无法解决每个对象实例在构造时分配内存所耗时间。我做了一个不精确的评估,相比DataSet,对象集合的性能损失大约占20%左右。
如果假定ORM并没有比传统的数据访问方式耗费额外的IO的话,除此之外,ORM再没有任何性能损失!
再回到前提条件:ORM并没有比传统的数据访问方式耗费额外的IO。这个条件成立么?
“ 由于ORM的实体对象定义已经固定,所以即使我不需要某些字段,也一样需要加载这些字段。 ”
OK,有的同学已经看出来了。额外定义一个视图的实体对象即可。定义这些视图的实体对象的确很麻烦,但是肯定比构造那些SQL并不断地维护它简单得多。
“ 当一张表中有1000万行数据时,实例化1000万个对象是不可能的。 ”
非常正确。难道你曾经成功地尝试过将1000万行数据加载到某个DataTable中并且没有性能问题?从应用的角度来说,在一个模型中包含的实例数超过500行就有设计不当的嫌疑。我对Google的抱怨是:当搜索结果超过1000个时都会令我抓狂。让我从1000行数据中找出我所需要的某一行,这是开发人员的思维,并不是用户的思维。如果能够在已有的结果中进行二次、三次或者多次进一步的筛选,可能更适合绝大多数人。我为什么不愿意在分页中花太多的精力,其原因也是如此。我认为用户的眼球只能接受100行以内的数据,超过这个行数就需要采用其它的方式,或者改善领域设计。所以,这个问题的答案是:你不可能需要一次载入1000万行。
“ 当应用系统整体性能欠佳时,因为隐藏了数据访问细节,从而无法找到快速优化的途径。 ”
不能同意。几乎每一个ORM框架都提供了非常可靠的数据库访问日志。通过这些日志分析性能损失将比直接使用SQL语句更可靠、更方便。
灵活性
ORM不够灵活?我完全不能理解,我甚至不知道这个不够灵活是与什么基准相比。相反,ORM可以让你灵活地替换数据库(当然这个优点并没有非常重要的意义);在修改数据库以后不需要修改服务层或者只需要进行简单的修改;可以对某个服务进行单独的测试;可以对服务进行不依赖数据库的、上下文一级的扩展;可以进行更好的层次设计;......
不能实现所有的查询条件?
如果是想表达“每一个Select语句可以通过面向对象的方式进行查询”的话,我觉得目前绝大部分ORM框架都已经很好地解决。我解决这一问题的基础是:我不提供超越SQL ANSI92的能力,但覆盖SQL ANSI92的所有功能。对于解决实际应用中的不足部分,采用运行时算法补充。Hibernate采用的是HQL这样的方式,基本上SQL能够做到的,HQL都无一例外可以做到。ECO采用的是OCL的方式,其功能可以完全覆盖SQL。我的框架所实现的查询目前我还没有发现无法解决并必须利用Native SQL来实现的(因此我无法理解Hibernate3为什么要提供这样的扩展)。Hibernate采用的策略是以面向对象为核心,换句话说,以持久化对象为终极目标,而以加载对象以持久化对象为前提。设计一个POJO,实例化,然后保存起来,下次使用的时候可以依样载入即可。大规模的查询并不是框架的核心目标。所以,如果你完全依赖Hibernate去持久化,我非常担心你将来是否有机会用你的数据积累去做数据仓库。而我的框架目标则不同。在持久化与加载两个目标间我没有主次之分。我也没有超前到MDA,我的对象模型仍然基于数据库的ER设计,我仍然提供一组非常清晰明了的数据库视图。
多表连接查询
如果需要将多表的连接查询结果转换成一个二维视图,显然需要你再定义另一个视图实体对象,将视图映射到对象模型。如果你仅仅是要在一个对象实例的某个属性中获得另外一个对象的集合,似乎这不是DAL方式的优势,而反而是ORM的优势。将多个对象所依赖的多个对象放到同一个上下文中,显然这是最好的一种方式。
统计查询
从理论上讲,ORM不适合做OLAP,不适合做太多统计查询。其实这一点,我的框架已经提供了非常好的解决方案,对Aggregate到面向对象的视图处理得非常好。
开发效率
提高开发效率仅仅是一个抽象的目标,具体的手段应该是两个方面:一是IDE和辅助工具;一是适合将任务分解成多个解耦的部分从而可以通过增加人员来提升总的开发效率。虽然ORM仅仅是开发环节中很小的一部分,但是却遍布应用系统中的每一角落,因而对开发效率影响较大。除了ORM,难道还有更好的选择么?
ORM后,原来精湛的SQL技能变得毫无用武之地,让人甚是失落,但这并不是ORM的过错。
总结: 作者旨在说明,有些人之所以没有认识到ORM的好处,是担心“ORM无法解决每个对象实例在构造时分配内存所耗时间”,但是根据业务需求,我们要创建的对象实例,在操作的效率差距上,几乎是感觉不到的。加之,使用面向对象的操作方法,增强对数据操作的易用性,ORM必将大行其道!我们在近期的项目中,使用了ORM的Nhibernate,因为在试水阶段,感觉编程很方便,但是运行起来,非常的慢,很是郁闷。知道是在构造对象实例消耗过多时间,于是在这方面做了优化,果然,效率提升很多。就像作者的意思,使用ORM,一定要把握好对象实例在构造时耗费时间的问题,让ORM的优越性,更好的体现出来!