也不仅仅是hibernate一个框架的问题了,其实可以上升到O/R Mapping的应用策略问题
几乎每隔几周就会出现类似的讨论,比如 主题: 有没有Hibernate的成功大型项目实现?Hibernate,憋脚的ORM框架
这说明这个问题还是很有讨论的必要。

过去的几次比较热烈的讨论我基本都看了,焦点主要集中在这几个方面:

1、以数据库为中心建模 VS 以领域模型为中心建模:
老开发人员大多倾向于前者,因为比较符合过去的开发习惯,另外他们强调数据库的生命周期大于App
向我这样的只有几年工作经验的往往会倾向于后者,因为这能更充分发挥ORM的威力,更符合OO,免去很多维护DB的繁琐工作。

2、Hibernate VS iBatis/JDBC:
担心失去对SQL待控制权,导致不能做优化,DBA反对
Hibernate是在JDBC之上的又一层框架,因此想当然的认为其性能不如iBatis/JDBC(我认为这个结论不成立,因为引入一个ORM层给了我们更多机会去优化性能,比如一二级缓存、lazyload、查询缓存,并且方式更优雅)。参考为什么ORM性能比iBATIS好?
担心OpenSessionInView模式有性能问题(http://www.javaeye.com/topic/17501)
Hibernate无法应付复杂查询(我认为这不是问题,HQL和criteria查询能力很强,再不济还可以用SQL啊)

3、对Hibernate等ORM框架能否胜任大型项目的怀疑:
其实项目大小不是技术选型的主要考虑,关键看项目类型,OLTP还是OLAP、广而浅型的还是窄而深型的、数据量大小等等,这些因素更能影响结果

4、Hibernate学习成本高
不可否认,相对于spring、struts,Hibernate是一个学习曲线陡峭的框架,但是我觉得综合考虑开发效率和长期收益,还是值得学习和采用的

其实有一个事实被很多人忽略了——Hibernate只是对JDBC的一个封装,因此它可以跟iBatis/JDBC在同一个项目中并存,就好比突击步枪和狙击步枪的关系,两者都有存在的价值和适用场合,不能互相取代。
但是,显然突击步枪是大量装备的通用武器,而狙击步枪是少量装备的特种武器

参考帖子:
OpenSessionInView会不会影响性能?
选择Hibernate还是iBatis?
选择Hibernate还是iBatis?
我为什么选择 iBatis 而不是 Hibernate(对于正在选型的人的建议)
Hibernate,憋脚的ORM框架
对迷茫于Hibernate/JPA的人提一些建议。
为什么ORM性能比iBATIS好?
评论
Ab.Yann 2008-04-28
ray_linn 写道
就一点就够让人讨厌了,hibernate天生就是贫血

是不是贫血,就看你向里面充多少血了,hibernate除了getter,setter方法外,对基于的方法都是透明的.
dabb 2008-01-15
另外,个人认为orm层在应用系统的整体架构里属于比较次要的部分,大部分情况下采用orm并不能提高多少生产效率,架构设计人员没有必要在该问题上纠缠不清。是否采用hb充其量只能算是架构设计人员和开发人员的个人喜好而已,无关大局。
dabb 2008-01-15
按个人经验,使用hibernate碰到的最讨厌的事情:
1.需要在设计模型时就需要考虑lazy load的问题
2.是否动态update,也需要在设计模型时作点考虑
当然上面的“问题”也不能算作问题,只是个人更倾向于将这些细节问题留到开发具体应用功能点的时候去考虑。特别是模型设计者和功能开发人员分开的时候,从职责上看这些问题更应该归到功能开发人员的责任上。设计模型时考虑这些问题,套句xp常用语,有点“过度设计”。
而jdbc(or ibatis)不存在该问题。所以现在的开发中我更倾向于使用jdbc方式的相对于 hb(或则其它orm,jdo等)更轻的持久层解决方案。
dabb 2008-01-15
按个人经验,使用hibernate碰到的最讨厌的事情:
1.需要在设计模型时就需要考虑lazy load的问题
2.是否动态update,也需要在设计模型时作点考虑
当然上面的“问题”也不能算作问题,只是个人更倾向于将这些细节问题留到开发具体应用功能点的时候去考虑。特别是模型设计者和功能开发人员分开的时候,从职责上看这些问题更应该归到功能开发人员的责任上。设计模型时考虑这些问题,套句xp常用语,有点“过度设计”。
而jdbc(or ibatis)不存在该问题。所以现在的开发中我更倾向于使用jdbc方式的相对于 hb(或则其它orm,jdo等)更轻的持久层解决方案。
gavin213 2008-01-15
受教了,LZ说的很透彻,以前这种贴都快看烂了.....
Aaron_Zhang 2008-01-14
Qieqie 写道
1、hibernate没有什么是“意料之外”的故事,一切都显得理所当然,若有意外,那应该归功于盲从,而非被盲从的对象

2、使用hibernate,我不用去“SQL 跟踪、优化”,看几眼,感觉一下就够了。优化也轮不到SQL,更多的是你的数据库策略上的非SQL层级的优化(比如索引)。SQL没什么好优化的,少读几个列? 没必要;表连接少一点?(不用看SQL,看Hibernte就可以看出来).

3、使用自写的SQL,那就真需要“SQL跟踪”了,你不知道你哪一个地方写错了,这够没意义,而且够烦。

4、使用Hibernate不需要大牛,只要不盲从,回到基本面,从reference开始。
不了解的,不踏实的,新碰到的,那就做做试验--磨刀不误砍柴功

先到此为止,算是对楼上部分观点的回复



说的不错
jwd001 2008-01-12
另外,原先之所以有多个关联表,而不是像robbin那样设计只有一个,可能出于以下原因:如果一个resume选择4个地区,3个行业,3个职位,那么一个关联表的就有4*3*3=36条记录,而多个关联表则只有4+3+3=10条记录
jwd001 2008-01-12
对于firmgoal的问题,我觉得可以直接在resume表上建标志字段,比如对行业参数加个industry char(30),(假设有30个行业选择),或用整型数的bit位表示,这样就没有关联表了.查询就用全索引扫描.
AK_47 2008-01-10
HIBERNATE有一些用法是不支持的

例如

1 左连接或右连接的时候,你只能连接它的子集(如果当初没有建立连接的话...)

2 部分COUNT无法计算,例如我查询某一个条件的条数,并且去处重复了,这个时候再统计数据就比较麻烦了

3 某些关联的查询在SQL里没有问题,但是同样或者类似的写法在HQL里就无法使用


所以我觉得如果不是有牛人作为技术支持的话,HIBERNATE最后不要用在大项目里,遇到越复杂的逻辑HIBERNATE用起来就越难以使用
jasongreen 2008-01-09
timerri 写道
我有几个预言......

1.orm工具将被oodb取代.....
2.数据库索引和数据将被分开处理
3.分布式数据将成为应用主流...

jdbc,iBATIS,hibernate真的有本质区别么?扳手和活动扳手的区别罢了.....当然,你也可以选择用钳子...



赞一个,第一条我认同
firmgoal 2007-12-28
bulargy 写道
robbin 写道

我仔细看了一遍你贴出来的执行计划,终于发现你关联查询慢的根源了!请看:


s.guid=r.stu_guid

你的关联查询关联外键上面根本就没有建立索引!这种关联查询会造成你的student表和resume表全表扫描,难怪会这么慢!

给student表的guid字段建立索引,然后给resume表的stu_guid字段也建立索引,再查询一遍,我保管你1秒钟查询完毕



期待firmgoal 的实际测试结果~~~~



我上面已经答复了啊,测试的时候就是已经有外键索引了。
bulargy 2007-12-28
robbin 写道

我仔细看了一遍你贴出来的执行计划,终于发现你关联查询慢的根源了!请看:


s.guid=r.stu_guid

你的关联查询关联外键上面根本就没有建立索引!这种关联查询会造成你的student表和resume表全表扫描,难怪会这么慢!

给student表的guid字段建立索引,然后给resume表的stu_guid字段也建立索引,再查询一遍,我保管你1秒钟查询完毕



期待firmgoal 的实际测试结果~~~~
firmgoal 2007-12-28
blowfisher 写道
你的表记录总量有多少? 不会是天文数字级的吧...
按道理超过1S就不太正常了,
我只对千万级的表测试过多种关联查询,完全可以做到毫秒内完成,前提是查询规则能合理用上索引。

试一下看这个?
select s.guid, ROWNUM as rowno 
   from student_base_info s 
      join resume r on s.guid=r.stu_guid 
where r.resumetime > to_date('2007-12-01','yyyy-mm-dd') AND rowno between 10000 and 10010


rownum不能直接进行<比较吧?需要用内嵌表。
blowfisher 2007-12-28
你的表记录总量有多少? 不会是天文数字级的吧...
按道理超过1S就不太正常了,
我只对千万级的表测试过多种关联查询,完全可以做到毫秒内完成,前提是查询规则能合理用上索引。

试一下看这个?
select s.guid, ROWNUM as rowno 
   from student_base_info s 
      join resume r on s.guid=r.stu_guid 
where r.resumetime > to_date('2007-12-01','yyyy-mm-dd') AND rowno between 10000 and 10010
firmgoal 2007-12-27
robbin 写道
firmgoal 写道
我希望达到的目标,数据库查询返回应该是毫秒级的(<1s)。在实践中发现大表关联基本上没有毫秒级的,因此,我还是强调我的观点,可以通过冗余来避免关联,减少IO。


我手里没有Oracle数据库,所以没有办法做相应的测试,但是我觉得你的查询结果不可思议,查询毫无道理的慢,除非你的student表和resume表的字段太多,或者包含了大字段。像我在MySQL上面做的查询,但凡有效利用索引的关联查询,都不会超过1秒钟。

我建议你再测试一下单表查询,单独select student表和select resume表,加上同样的where条件和分页语句,看看执行时间。如果你的student和resume表关联查询这么慢的话,单独select resume表也不可能快的起来。

另外你的student表多少个字段?有没有blog/clob/long型的大字段,现在有多少条记录,表存储空间多大? resume表有多少个字段?有没有blob/clob/long型大字段,现在有多少条记录,表存储空间多大?这个信息很重要!

实际上关联查询并不一定慢,只要关联外键有索引,where条件有效索引可以约束扫描的表记录,关联查询并不见得会比单表查询慢,关键还是看查询语句实际造成了多少磁盘IO。所以查询性能低下的根源不在于关联查询,而在于表扫描造成的IO。


我又重新多执行了几遍查询,有可能是下午人多的时候,数据库有点慢(我是在生产机上做的)。Student+Resume关联查询大概是4-5秒,单查Resume表0.4-0.5秒。这两个表都没有B/C/L字段。Student表字段多一些,100来个,如果单取Student表的几个字段做关联查询的话,速度要快,大概1-2秒。

另外,关联外键目前有索引,RESUME_STU_GUID_IDX。慢得那么离谱可能是执行的时候,赶的时候太不巧了。应该我现在测试的时间准确。执行计划中没出现RESUME_STU_GUID_IDX,应该是这个索引操作包含在NESTED LOOPS里了,如果没有关联外键的话,应该是用SORTED MERGE或者HASH JOIN连接方式。
robbin 2007-12-27
firmgoal 写道
blowfisher 写道
引用
select * from student s join resume r on s.guid=r.stu_guid where r.resumetime > to_date('2007-12-01','yyyy-mm-dd')
已选择86232行。
已用时间: 00: 02: 24.09


返回的结果集86232行,这么大,又是 SELECT ALL ,能快到哪去,

这样的测试没有实际意义,不Crash已经很幸运了
加上 LIMIT 50, 再测吧


我承认,全选出来占了太多IO,不过光LIMIT没有意义,COUNT STOP很快,弄个有意义一点的,翻页:
select * from (select s.*, ROWNUM as rowno from student_base_info s join resume r on s.guid=r.stu_guid where r.resumetime > to_date('2007-12-01','yyyy-mm-dd') ) inner where rowno between 10000 and 10010

已选择11行。

已用时间: 00: 00: 29.05

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1072 Card=3371 Bytes
=26944403)

1 0 VIEW (Cost=1072 Card=3371 Bytes=26944403)
2 1 COUNT
3 2 NESTED LOOPS (Cost=1072 Card=3371 Bytes=2861979)
4 3 TABLE ACCESS (BY INDEX ROWID) OF 'RESUME' (Cost=398
Card=3371 Bytes=161808)

5 4 INDEX (RANGE SCAN) OF 'RESUME_RESUMETIME_IDX' (NON
-UNIQUE) (Cost=24 Card=3371)

6 3 TABLE ACCESS (BY INDEX ROWID) OF 'STUDENT_BASE_INFO'
(Cost=2 Card=1 Bytes=801)

7 6 INDEX (UNIQUE SCAN) OF 'SYS_C0013212' (UNIQUE)


还是不尽人意。


我仔细看了一遍你贴出来的执行计划,终于发现你关联查询慢的根源了!请看:


s.guid=r.stu_guid

你的关联查询关联外键上面根本就没有建立索引!这种关联查询会造成你的student表和resume表全表扫描,难怪会这么慢!

给student表的guid字段建立索引,然后给resume表的stu_guid字段也建立索引,再查询一遍,我保管你1秒钟查询完毕

robbin 2007-12-27
firmgoal 写道
我希望达到的目标,数据库查询返回应该是毫秒级的(<1s)。在实践中发现大表关联基本上没有毫秒级的,因此,我还是强调我的观点,可以通过冗余来避免关联,减少IO。


我手里没有Oracle数据库,所以没有办法做相应的测试,但是我觉得你的查询结果不可思议,查询毫无道理的慢,除非你的student表和resume表的字段太多,或者包含了大字段。像我在MySQL上面做的查询,但凡有效利用索引的关联查询,都不会超过1秒钟。

我建议你再测试一下单表查询,单独select student表和select resume表,加上同样的where条件和分页语句,看看执行时间。如果你的student和resume表关联查询这么慢的话,单独select resume表也不可能快的起来。

另外你的student表多少个字段?有没有blog/clob/long型的大字段,现在有多少条记录,表存储空间多大? resume表有多少个字段?有没有blob/clob/long型大字段,现在有多少条记录,表存储空间多大?这个信息很重要!

实际上关联查询并不一定慢,只要关联外键有索引,where条件有效索引可以约束扫描的表记录,关联查询并不见得会比单表查询慢,关键还是看查询语句实际造成了多少磁盘IO。所以查询性能低下的根源不在于关联查询,而在于表扫描造成的IO。
firmgoal 2007-12-27
我希望达到的目标,数据库查询返回应该是毫秒级的(<1s)。在实践中发现大表关联基本上没有毫秒级的,因此,我还是强调我的观点,可以通过冗余来避免关联,减少IO。
firmgoal 2007-12-27
blowfisher 写道
引用
select * from student s join resume r on s.guid=r.stu_guid where r.resumetime > to_date('2007-12-01','yyyy-mm-dd')
已选择86232行。
已用时间: 00: 02: 24.09


返回的结果集86232行,这么大,又是 SELECT ALL ,能快到哪去,

这样的测试没有实际意义,不Crash已经很幸运了
加上 LIMIT 50, 再测吧


我承认,全选出来占了太多IO,不过光LIMIT没有意义,COUNT STOP很快,弄个有意义一点的,翻页:
select * from (select s.*, ROWNUM as rowno from student_base_info s join resume r on s.guid=r.stu_guid where r.resumetime > to_date('2007-12-01','yyyy-mm-dd') ) inner where rowno between 10000 and 10010

已选择11行。

已用时间: 00: 00: 29.05

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1072 Card=3371 Bytes
=26944403)

1 0 VIEW (Cost=1072 Card=3371 Bytes=26944403)
2 1 COUNT
3 2 NESTED LOOPS (Cost=1072 Card=3371 Bytes=2861979)
4 3 TABLE ACCESS (BY INDEX ROWID) OF 'RESUME' (Cost=398
Card=3371 Bytes=161808)

5 4 INDEX (RANGE SCAN) OF 'RESUME_RESUMETIME_IDX' (NON
-UNIQUE) (Cost=24 Card=3371)

6 3 TABLE ACCESS (BY INDEX ROWID) OF 'STUDENT_BASE_INFO'
(Cost=2 Card=1 Bytes=801)

7 6 INDEX (UNIQUE SCAN) OF 'SYS_C0013212' (UNIQUE)


还是不尽人意。
blowfisher 2007-12-27
引用
select * from student s join resume r on s.guid=r.stu_guid where r.resumetime > to_date('2007-12-01','yyyy-mm-dd')
已选择86232行。
已用时间: 00: 02: 24.09


返回的结果集86232行,这么大,又是 SELECT ALL ,能快到哪去,

这样的测试没有实际意义,不Crash已经很幸运了
加上 LIMIT 50, 再测吧
发表评论

提醒: 该博客已发表在公共论坛,博客所有留言会成为论坛回贴,留言请注意遵守论坛发贴规则

您还没有登录,请登录后发表评论

daquan198163
  • 浏览: 71832 次
  • 性别: Icon_minigender_1
  • 来自: 吉林->北京->上海
  • 详细资料
搜索本博客
我的相册
F7063e49-a7bb-47bc-8dd9-89c20c8b52d3-thumb
4939384202000irl_0
共 3 张
最近加入圈子
存档
最新评论