Lazy Load vs Immediately Load?

LazyLoad是在实体实例加载中一种可选的策略,在Hibernate2中支持引用的LazyLoad,在Hibernate3中更支持任意类型属性级的LazyLoad。
大概评估了一下,LazyLoad有以下好处:
1.提高运行时的响应度。执行三个SQL语句显然比执行一个SQL语句快。
2.节省内存。一次性加载全部的依赖肯定会耗费更多的内存。
3.不用担心循环引用。因为互相引用的两种不同的实体是在不同的时期加载的。
4.对特殊的BLOB字段(例如较大的图片)似乎必须采用LazyLoad。
看起来似乎LazyLoad是一个持久层框架必备的功能。况且实现LazyLoad是件非常容易的事情。
但是,思考再三,最终全面放弃LazyLoad。理由是:
1.数据库连接的成本高于数据库执行的成本,采用LazyLoad虽然会减少数据库连接时间,但是却增加了连接的次数,导致最终数据库成本增高。
2.可以强制BLOB字段采用分割映射----即将键与BLOB单独映射到另外一个实体中。当然,是采用两张表还是一张表全凭开发者自己选择。如果是映射到同一张表,则该字段必须为可空(因为这个字段的读写显然与其它字段的读写不在同一个SQL语句中)。这样可以带来一些额外的好处。在不需要BLOB属性的时候完全不用考虑这个属性的存在。
3.关于内存的占用,通过实际运行的测算,不会比LazyLoad占用的内存多过一倍。如果某一次Load出的实例为10000个,那么它所依赖的其它实例则一定不会超过10000行。因为每次依赖的过程是一个循环递减的过程。
4.在Kanas.net中需要在应用上下文中保存实体的加载状态,以满足DataSet的要求。对部分加载的实体是通过已加载的约束与请求的约束进行比对,通过逻辑运算进行优化,以尽量减少从数据库返回的行数。

posted on 2005-08-10 02:40 双鱼座 阅读(2061) 评论(16)  编辑 收藏 网摘

评论

#1楼  2005-08-10 08:54 Teddy's Knowledge Base      

2:40发帖呢~~佩服~~

确实,要透明支持lazy load和非lazy load会大大增加代码的复杂度,但是,你说的几点全面放弃lazyload的理由,与其说是理由看起来更像借口似的.

我正在考虑是不是可以在构造domain obejct的时候,由用户指定本次构造是否采用lazyload。因为实际的对象的使用中常会有这种情况,比如,我要修改一个人员的基本信息,但是这个人员类和很多其它的相关实体关联,但这些信息如角色可能和本次修改完全无关,但有时候我使用人员类的时候确实真的要用到很多它的相关实体类属性的信息。偏重支持哪一个都不完美,因此,我想在在构造具体的类时制定本次构造是否是fullload这种形式可能比较好。虽然这会造成部分不透明,但是,这种不透明不见得违背oo原则。打个比方:我有一台笔记本电脑,即使我常带在身边,但如果某次你叫我出去打牌,不需要我带上什么其它东西时,我就完全没必要fullload我所有的装备;但如果是谈业务的话,也许你需要我fullload,因此给调用这一个提要求的机会,语义上是比较自然的。   回复  引用  查看    

#2楼  2005-08-10 13:08 James      

对于主从表,我的主表一条记录可能对应从表1000条记录,那你不使用延迟加载的话,客户的体验是否好呢?

  回复  引用  查看    

#3楼 [楼主] 2005-08-10 13:11 双鱼座      

@Teddy's Knowledge Base:
明白你的意思了。不过不太同意的的意见。
懒惰加载与立即加载的区别并不在于你需要在Load一组Employee的时候同时Load与Employee相关的全部信息,即使你没有LazyLoad也无法Load出来。原因是:Employee并不依赖相关的其它信息,就象你其实不依赖笔记本(因为你要打牌),但是笔记本是依赖你的。在Load一个Employee的受教育情况时,你必须Load这个Employee,相反则不然。
举个例子吧。你要加载某段时间所有购买XXX产品的订单项。如果是LazyLoad就只需要加载订单项,但是当需要获取订单项所在订单的日期的时候你不得不去再次启动数据库连接加载这个订单项所在的订单。但是如果你要加载某段时间的所有订单,我不一定关心每个订单所有的订单项。如果需要可以手动或自动加载,但不能叫LazyLoad。
是否违背OO原则我觉得并不重要,我一直这样看。只要是合理、实用、优雅,OO不OO的并不重要。
在.net下的持久层框架对业务对象生命周期的要求与java下是不一样的。也许调用Load的过程并不是由业务代码显式发动的,很可能来自一个DataSet的请求。我无法想象,一个结构尚未构造完毕的DataSet在UI层会造成什么后果。所以我比较侧重去评估立即加载的害处而不是懒惰加载的好处。
事实上在我目前的项目中,是由通过解析一组Xml文档来调用实体的Load,想控制的话只能通过增加Xml钩子来实现了。   回复  引用  查看    

#4楼  2005-08-10 13:47 QuitGame      

不OO 就不优雅。

OO 是一套科学理论。   回复  引用  查看    

#5楼  2005-08-10 14:09 Teddy's Knowledge Base      

“在Load一个Employee的受教育情况时,你必须Load这个Employee,相反则不然”
——我觉得这个要看你的O/R具体怎样映射,比如如果表Employee存储人员信息,表EmployeeEducation存储教育信息,两表采用主键关联,共享相同的主键ID值(Hibernate中就有这样的关联方式),那么load教育信息是根本不需在此载入Employee。

你举的这个订单和订单项的例子我感觉也有问题,感觉没有说明清楚上面的Employee你想说明的问题:实际上从订单-〉订单项-〉相关产品这个顺序应该是可以了lazyload的,反过来就不一定,这取决于订单项实体类是否包含到订单的反向引用,要不然顶多只是一次对关联表的查询,确实就不是lazyload了。

“只要是合理、实用、优雅,OO不OO的并不重要”——这个我非常同意,实际上,特别作为一个自己会成为主要用户的framework来讲,易用性、基于其开发能不能减少自己的工作量是肯定会被优先考虑的的因素:)

现在好像有很多人在研究基于DataSet来实现Unit of Work的好处,其实我觉得,鉴于创建一次数据库连接的开销其实远小于对一个连接执行多次查询的开销,辅以连接池(.Net下默认的ADO.Net sqlserver provider其实已经默认提供很好的连接池支持了,Oracle的ADO.Net db provider也是,只要在connectionstring中做好设置即可,比 Java下工作量已经减少了很多了)和语句、参数缓存的优化,实际上不采用Unit of Work的额外开销其实已经很少了,完全可以用更优雅的方式来组织一个事务的执行过程。   回复  引用  查看    

#6楼 [楼主] 2005-08-10 14:14 双鱼座      

@QuitGame:
OO是科学的理论没错,但是科学与优雅之间没有必然的联系。AOP也不OO,但是优雅。   回复  引用  查看    

#7楼 [楼主] 2005-08-10 14:32 双鱼座      

@Teddy's Knowledge Base:
在.net下自动产生一个DataSet正是业务层对UI的反射控制(以前我曾经发表过类似的看法,就象PropertyGrid一样)。当然,其实这一切并不是我所强调的,但是这的确是在java中不怎么需要考虑的问题。
完整的lazyload应该是一种非常纯净的----不考虑任何引用关系,包括类似订单项对订单的关联引用。而自订单 -> 订单项的过程是否lazy,应该由实体类型自己来定义,框架没有理由干预。
教育信息与Employee间没有理由成为共享主键ID,因为基数不同。例如接受本科、硕士、博士三次不同的教育各需要一个ID,没可能与Employee同基。O/R映射无法改变内在的实体关系,往往实体关系与加载及持久化过程相对称。
共享主键可以直接看成是继承关系,无论是形式上还是实质上,按继承关系处理也许不够优雅,但肯定是正确的,代价也不会额外增加。   回复  引用  查看    

#8楼 [楼主] 2005-08-10 14:37 双鱼座      

@Teddy's Knowledge Base:
对了,对XMI的支持......最近看了一些资料,你是正确的。我无法在目前这个版本中支持XMI,但是在下一个版本我一定会实现对XMI的支持,希望就这方面有机会和你多多沟通。ECOII也是这样。不过UML建模成本远远高过ER建模成本。这也许是MDA的瓶颈所在?   回复  引用  查看    

#9楼  2005-08-10 16:06 Teddy's Knowledge Base      

@双鱼座:

"订单 -> 订单项的过程是否lazy,应该由实体类型自己来定义,框架没有理由干预"----这样的话确实会干净一点,我前面说的做法确实对使用者的主观假设多了点,仔细想来确实不太必要,还是把这种类似的细颗粒开放给用户来设置比较好。

对于这种关于调整ORM细节的配置文件我有一点疑惑,主要是,一般来讲,为了减少工作量,基本的默认配置文件肯定会用工具来帮助生成,但是,如果改过一些细节过后,如果模型变了需要重新生成配置文件是怎么处理好呢?能想到两种处理方式:一种是为每个实体类生成一个配置文件,这样有新的改动时,只需覆盖部分;还有一种是在有一个主配置文件的基础上,允许在一个自定义的配置文件中定义优先级高于默认配置的配置信息,这样自定义信息就不会干扰到默认配置了,典型的例子就是asp.net的machine.config和web.config。我比较倾向于后者,不知道你的framework中是怎么设计的?

关于XMI,我只能说感觉我需要的信息他总还是能定义的,目前来讲,比较简单的办法还是自己定义一个model schema,作一步xmi到model schema的转换实现上比较简单。从长远来讲,我在设想是不是可以充分使用uml的扩展特性,定义一套辅助的定义库,专用于我的framework,从XMI的定义来是允许这样的扩展的,但是最好自己实现一个基于特定扩展的可视化建模工具才比较有意义。

一个好的framework设计,在基本特性之外,我觉得越来越应该考虑code-generating tool friendly了,希望更多人多考虑这一特性!

“在.net下自动产生一个DataSet正是业务层对UI的反射控制”----不知道你这算不算业务建模/UI映射的范畴,或者说只是对asp.net的ui控件更friendly的设计,不管怎么样,UI这一块怎么才能减少工作量、加快开发效率确实还是个值得研究的大问题~~   回复  引用  查看    

#10楼 [楼主] 2005-08-10 20:35 双鱼座      

@Teddy's Knowledge Base:
关于映射的配置...汗...我根本不愿意将配置作为必须的东西。虽然我提供了使用配置加载实体元数据的API(不包括详细元数据清单),但是这并不是强制性的。似乎我更倾向于以实体类配以CustomAttribute或者实体接口配以CustomAttribute来代替映射的配置。我生成代码的工具提供了直接编译为dll的能力,我希望在结构变化的情况下重新编译这个程序集,部署的问题好象无法回避,毕竟业务层的代码中需要增对这些新加的属性的访问或者删除对已取消的属性的访问,仅仅元数据层实现热部署没有太大的意义。元数据层不定义任何实体信息----这和DataSet方式访问没有什么区别,同时也失去了编译期的类型检查。所以我宁可在框架与业务层之间增加一个硬编码的实体层,并且抵制任何形式的元数据冗余。
我宁愿将一些常用的逻辑通过一个工具定义到一个XML文档中,框架从这个文档中获取元数据信息生成UI层所需要的数据集;UI层根据XML中的元素定义生成相应的界面,这样公共的UI层(例如网格、Chart、地图等等)根本没有必须了解数据源的任何细节,专心将这个UI元素显示好就行了。同时,业务层只负责定义这个XML文档,UI层如何展示,是asp.net还是WinForm就根本就不必关心了。事实上,UI的元素类别总是有限的,你可以为每一类UI元素准备一套Schema,将业务层与UI层分割开来。记得03年的时候我就总结了九类UI,这九类以外的UI元素少之又少,即使有,再专门定义一个Schema作为业务层与UI层的公共约定,也不会花费太多功夫。所以,面向UI类别来思考障碍应该会少一些。

Kanas.net 1.3必须尽快发布了。所以我每天必须工作到很晚,早晨还得按时上班。希望我在框架中的一些思想会对你有些启示。例如,约束子及其运算机制、数据囊机制,枚举映射机制等等,虽然都是一些细节,但我相信对你的LiteMDA应该会有所帮助。例如从interface到通过emit在运行时实现接口,我都有现成的解决方案并通过了有效性、资源占用以及性能方面的大量测试。   回复  引用  查看    

#11楼  2005-08-10 21:19 Teddy's Knowledge Base      

"似乎我更倾向于以实体类配以CustomAttribute或者实体接口配以CustomAttribute来代替映射的配置"----你这种也是一类被很多人使用的配置方式,和将元数据独立出来的方案相比,应该说各有千秋,我个人来讲更倾向于“将元数据独立出来的方案”,觉得更灵活一点,比如可以根据情况动态更改部分配置信息。倒不是说,就不需要一个“硬编码的实体层”,实际上这个曾肯定是要的,反正也使用工具生成的不是什么工作量。

说道,独立出来的配置文件,entlib中的configuration有一点不错,就是,他会动态检测所管辖的所有configuration文件,运行时的更改他也会自动识别和缓存,这样利用该特性,我就可以在运行时动态的配置如某个类的某属性是否lazyload甚至插入一些injection,不过,当然也是在至少接口不变的前提下。再辅以将动态生成的默认配置文件和包含自定义设置配置文件分离的方式,在实体类结构变化时重新生成时,需要做的改动就能做到最少,也不会发生意外的覆盖自定义设置的情形,应该也会比较优雅。

你关于Business->Xml->UI的这个方案的说明其实很多人(包括)都进行过考虑,传统的做法是在Xml上加上一层Xslt来显示,但是,工作量太大且对显示的变更又不够灵活;你这种将XML构造成DataSet并充分利用Asp.Net/WinForm控件的绑定机制的方案确实是很好的方案,值得推崇。

真的是期待你的Kanas.net 1.3好久了,你的“约束子及其运算机制、数据囊机制,枚举映射机制等等”确实都是我最想看到的东西,到时看看我基于范型重写过后会不会发掘出更多很好应用来,多谢你的共享!

最后,还要提醒您注意身体这个本钱了~~   回复  引用  查看    

#12楼  2005-11-09 19:34 小唐 [未注册用户]

Business->Xml->UI :)遥想Barton当年,CXS初建了...

Oh,my God!大家到了哪儿都是大家,正象偶到哪儿都是菜鸟一样.   回复  引用    

#13楼  2007-10-29 10:55 mydotnet1999 [未注册用户]

对“况且实现LazyLoad是件非常容易的事情”,我很是不解。一般做延迟加载,必须实现动态代理,这个其实已经很麻烦了,难道有非常轻松简捷的方法吗?

另外,再真诚请教“双鱼座”一个问题,如何让不带virtual的属性支持延迟加载?左思有想,无法解决。   回复  引用    

#14楼 [楼主] 2007-10-29 13:49 双鱼座      

@mydotnet1999
想必是你没有下载我的源码。在.net环境下。Mixin还是一个遥远的梦想,所以动态代理是非常困难的。
我的解决方案的前提是:所有的属性获取方法必须调用基类的方法,这样当然就简单了。   回复  引用  查看    

#15楼  2007-10-30 10:11 mydotnet1999 [未注册用户]

谢谢指教,我下载你的代码学习学习看。   回复  引用    

#16楼  2008-04-09 00:01 蓝奇高级验证码识别引擎QQ:631753663 [未注册用户]

出售蓝奇高级验证码识别引擎,可准确识别新浪动网淘宝CSDN等多种复杂验证码。

输出为一个标准DLL,可供VB,VC,Delphi,C#.NET,VB.NET,模拟精灵,按键精灵等多平台调用,调用方法简单,几行代码即可完成。独具特色的边缘检测字符分离、旋转倾斜纠正和通用字符匹配算法(无论字体和大小), 使得该引擎对于像新浪、动网、淘宝、CSDN等多种验证码均有不错的识别率,是一款效果较为理想的验证码识别引擎。附详细的调用实例和代码注释等相关技术文档。

官方网站 - http://***/yzm_advocr
识别效果怎么样一试就知道 - DEMO下载 http://***/yzm_advocr/advocr.rar
  回复  引用    





标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
Google站内搜索

相关文章:

相关链接:
 

导航

<2007年10月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

统计

与我联系

搜索

 

常用链接

留言簿(31)

我参与的团队

我的标签

随笔档案

文章分类

相册

芸芸众生

最新评论

  • 1. re: ORM之硬伤
  • @田景
    没有人说ORM是万能的,也没有人说什么都使用ORM。
    我看了你的“简单的ORM”,不过真的很像个玩具,难怪你欢迎我下载玩玩了。
  • --双鱼座
  • 2. re: ORM之硬伤
  • ORM不是万能的,我也不会赞成在项目中什么都使用ORM。有时候使用ORM可能导致一定的学习成本。 我曾自己实现了一个简单的ORM,可供朋友们参考参考。同时也写了几篇配套Blog文,介绍了这个东西,欢迎...
  • --田景

阅读排行榜

评论排行榜