鉴于反复讨论hibernate适用性问题,希望有定论

Robbin:

其实围绕Hibernate的话题,我都已经说过不下30遍,以致于最近两年以来,我对所有Hibernate的问题都不愿意再回应。另外最近一年多来,使用Rails的ActiveRecord,让我对ORM的认识又加深了很多,其实对于那么多争议的问题,最好的解决办法就是自己去实践。对于自己没有去实践过的东西,争是争不出来什么的。
-------------------------------------

引用

1、以数据库为中心建模 VS 以领域模型为中心建模:
老开发人员大多倾向于前者,因为比较符合过去的开发习惯,另外他们强调数据库的生命周期大于App
向我这样的只有几年工作经验的往往会倾向于后者,因为这能更充分发挥ORM的威力,更符合OO,免去很多维护DB的繁琐工作。
-------------------------------------
数据库设计三大范式如雷贯耳,但作为非科班出身的我直到两个月前竟然都不知道三大范式究竟是什么。那么三大范式是什么?
-------------------------------------

引用

第一范式(1NF):数据库表中的字段都是单一属性的,不可再分。这个单一属性由基本类型构成,包括整型、实数、字符型、逻辑型、日期型等。
第二范式(2NF):数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖(部分函数依赖指的是存在组合关键字中的某些字段决定非关键字段的情况),也即所有非关键字段都完全依赖于任意一组候选关键字。
第三范式(3NF):在第二范式的基础上,数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合第三范式。所谓传递函数依赖,指的是如果存在"A → B → C"的决定关系,则C传递函数依赖于A。

-------------------------------------
两个月前当我购买了一本《MySQL权威指南》,翻到三大范式的定义的时候,我内心巨震,三大范式简单总结一句就是消除冗余,单纯依赖关系。不允许数据库表出现冗余字段,不允许表之间多重依赖,因此符合三大范式设计的数据库模型其实和你按照面向对象思想去建模得到的数据库模型是一样的。
所以不论你是从数据库为中心建模,还是你以领域模型为中心建模,你应该最终得到一个一致的数据库模型之所以导致数据库建模和OO建模的不一致,是因此传统的数据库建模从来都是违背三大范式的。而我们在过去经常说的一句话就是:为了数据库查询性能,我们需要多加一些冗余字段,不一定非要遵循三大范式......
所以不要再说什么数据库设计和面向对象设计导致的数据模型冲突的话,不是他们冲突,是你违背了三大范式,自己制造出来的冲突。
-------------------------------------
引用

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啊)

-------------------------------------
JavaEye网站的数据库设计是面向对象为中心的设计,但是拿三大范式来衡量,大部分设计都是吻合的,而我们的数据库缓存命中率在90%左右。缓存服务器的流量是数据库服务器流量的2.5倍之多。事实上我们有很多地方的查询尽量避免join,宁可让他n+1,这样速度反而更快,缓存命中率更高。
例如我们现在把帖子的内容字段拆分出来,单独放在一个post_texts表里面。这样posts表实际上只有35MB,而post_texts表有1GB。每次显示一个post,都会用主键去load post_text,命中缓冲。不需要查数据库,不需要去碰那个1GB的大表。
要充分发挥ORM的缓存优势,就必须把表设计的尽量细颗粒度,消除冗余和多重依赖,最终可能是相当多的小表,表之间通过主外键关联,但是关联关系都是单一的。那么这种追求面向对象的数据库模型是非常符合三大范式的。
-------------------------------------
引用

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

-------------------------------------
我只想举一个例子,Google在使用Hibernate,并且Google开发了一个叫做Hibernate Shards的分布式工具,将Hibernate运用在大规模分布式数据库环境当中,Hibernate Shards现在也是开源的,在Hibnerate网站上面就可以找到文档
-------------------------------------
引用

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

-------------------------------------
有时候参考着看看Rails的ActiveRecord,你才能发现ORM的乐趣。横向对比一下,你的思路会开阔很多,认识也会客观一些。

推荐有空阅读我写的相关文章:
漫谈应用缓存的命中率问题
为什么ORM性能比iBATIS好?
缓存简述

 

有一点必须承认,Hibernate虽然是一个功能非常强大的ORM,但是他在使用上面的陷阱也非常多,稍一疏忽就可能导致性能问题,所以真正把Hibernate用得好的项目非常罕见(当然也有用得好性能非常棒的)。即使是Rails的ActiveRecord,如果不注意,也很容易导致性能上面的问题,当然ActiveRecord功能简单的多,所以问题不像Hibernate那样突出。另外ActiveRecord的log输出的SQL非常易读,所以比较容易及时发现问题,不像Hibernate的log输出的SQL,根本就不是给人看的,出了问题很不容易发现。

我认识的很多相当资深的开发人员其实也不能够正确的认识ORM的作用,对Hibernate持相当否定的态度。我觉得这种状况一点都不奇怪,其实我自己也是在用了Rails的ActiveRecord,并且在JavaEye网站摸索了那么长时间,才对ORM能够有一个全面的认识的。

总之,follow your heart! 用你自己认为是正确的方式去实践和总结、不要理会别人的观点。

 

说到访问数据库的性能问题,其实用不用ORM,或者用不用iBATIS,这些都是皮毛,甚至用不用缓存,怎么用缓存,也没有触及到本质问题,真正的本质在于“数据库的瓶颈在于访问数据库文件的磁盘IO,尽量减少数据库服务器的磁盘IO才能从本质上提高数据库吞吐量”围绕这个本质,需要你从操作系统层面,数据库层面,应用程序的架构设计,缓存方式和应用程序框架方面进行通盘的考虑,至于说用不用Hibernate只是很小的一个战术层面而已
=======================

lgx522:

以前对三大范式印象太深,以致于一直是采用DB建模,最后设计出来的结果基本上是符合OO的,还真是殊途同归,所以ORM用得很爽。Hibernate有些复杂了,用起来还是要琢磨太多东西。最近用ActiveRecord,这才真正有飞起来的感觉。
另外说一点,大家不要太迷信那些所谓DBA的鬼话,好像离了冗余就没办法过日子。事实上经过良好设计符合第三范式与及OO的数据库应用,性能是相当高的,并且可以利用中间层缓存解决大部分性能问题。那种想以DB为中心搞定一切的错误思想是过时了。
在这种借口下,太多既不符合范式,也不符合OO的RAD垃圾系统横行市场,已经令人无法忍受了。

=======================

引用

就我自己使用hb的经验来看,其实我也认同很多性能问题其实都是不洽当的使用hb或者错误的数据库设计、错误的编程模式造成的。比如:在我自己负责的多个项目中就发现很多程序员喜欢在循环中去做一些查库操作;或者条件查询时根本就不使用分页查询;或者在不知道什么是lazyload以及get方法会引起查库操作等等的情况下。就在循环当中去调用get方法。
说实话:我在建行的很多j2ee项目中【包括建总行级的项目】都发现了以上的编程模式造成的性能问题,并且自己也亲自去解决优化过这些问题。
但是很多银行的所谓“高人”们在一遇到这种问题时往往会做出类似“看看,java性能确实不好”、“hb有性能问题”这样的结论。
其实我只是觉得非常的好笑。采用错误的编程模式,不管你用hb还是jdbc还是ibatis都会有性能问题的!!
-------------------------------------
是的,任何编程方法都会有自己的陷阱,讥刺Java性能不好,那C++程序员写的代码弄不好就把操作系统搞crash的又怎么说?

RoR的ActiveRecord照样有陷阱,他的1:n关系当中的_count魔法字段当不使用counter_cache声明的时候,在update操作当中会带来致命的性能问题。比方说topics表当中有一个posts_count字段,而topic和post有1:n的关系声明,那当程序员手工更新posts_count字段的时候,ActiveRecord就发送一条: select * from topics的SQL,把整个topics表全部抓出来,可怕吧!

程序员编程自己不注意代码质量,就是不用ORM,光用JDBC,难道就写不出来烂代码?难道Hibernate没有问世之前,Java程序员从来就不会碰到访问数据库的性能瓶颈吗?我们2000年的时候写的JDBC烂代码不使用榜定变量,导致Oracle数据库每周都要crash一次。

-------------------------------------
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。

 

我仔细看了一遍你贴出来的执行计划,终于发现你关联查询慢的根源了!请看:
s.guid=r.stu_guid
你的关联查询关联外键上面根本就没有建立索引!这种关联查询会造成你的student表和resume表全表扫描,难怪会这么慢!
给student表的guid字段建立索引,然后给resume表的stu_guid字段也建立索引,再查询一遍,我保管你1秒钟查询完毕

转载于:https://my.oschina.net/sniperLi/blog/482886

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值