|
锁定老贴子 主题:不做技术的奴隶
该帖已经被评为精华帖
|
|
|---|---|
| 作者 | 正文 |
|
最后更新时间:2007-06-02
1. 库表关系的复杂度,首先取决于需求,不取决于设计,设计能力强的人,也要遵守库表设计的规范,从巴克斯三个范式上,原则上也要遵守。不能说用了Hibernate,自己的库表设计能力就强了。不能为了用Hibernate,就去一味批判复杂的关系不对。复杂的关系设计对不对,首先取决于是否有复杂的需求,其次才取决于设计者的能力。 2. 只要你用的是关系数据库,就必须要明白,为什么叫关系数据库,而不叫面向对象数据库,把面向对象的那些观点,拿到库表设计上,后期维护和调优上,你要担起责任,不能让开发人员替早期决策人员擦屁股。我见过有的人,打着OO和扩展性的旗号,硬生生的把一个表,拆成了三个表,而这三个表,本来,只需要增加一个类型字段,再做一些冗余,就可以是一个表。现在查询时,还要把这三个表Union到一块来查。当需求变更时,增加一个字段,不仅要改变三个类,还要改变三个表,简直是乱伦。 3.One-One的库表设计,对于DBA来讲,并不是一个best practice的设计。不能为了Hibernate,刻意把大表拆成小表,再用几个小类,做成One-One的映射关系。整体性,是不能随便的分割,毕竟开发人在调试、测试和维护的时候,更喜欢看数据库里的数据,本来一个SQL,就查出来,现在要到多个表中去查。 4. 增删改存的实体维护 5. 你需要写原生SQL吗 有人会说,Hibernate也支持写SQL,但是写代码当中,就失去了原来基于Hibernate的DAO的简洁性。那个DAO一点也不简洁,如果你将动态拼SQL的代码也放在DAO当中,那个DAO就会充斥大量的If 。。Else。。之类的语句,一坨一坨的,非常的壮观。 还有人会说,Hibernate也支持命名查询,将SQL写在映射文件当中,但是命名查询,只支持占位符固定的情况,也就是说,where a = ? and b = ? and c=?,是三个问号,就是三个问号,传参时,少一个都不行。但是很多项目的查询,都是动态的,也就是说用户选了这个查询条件,才会生成这个占位符的。 Hibernate办不到。
5. 调优 后期调优,既然是后期调优,我想就一定是遇到了瓶颈,可能要在库表上做冗余,可能要检查那些Bad SQL,可能要修改代码,可能要动用DBA层次上的一些调优手段,那么调优越深入,Ibatis的优势就越能体现出来,比如说增加临时表,中间表,增加冗余字段等。 6. 开发速度 问题在于,怎么样算是一个Hibernate高手,别看论坛上,那么多人,群情激奋的在说Hibernate的好,有谁真的是高手? 7. 平台移植性 8. 维护性 HSQL好阅读吗,From order,确实很简单,但实际当中,这跟拿HelloWord做例子,有什么区别? 我的项目当中,在Hibernate方面,还有一个比我更强的人,他也很烦去看Hibernate打印出来的sql,看上老半天,再调上老半天,项目进度,嗖嗖的过去了。 水平越高的人,任务越重,很少有时间和耐心去解决一般性的问题。 最终的运用: 在基于Spring的容器事务管理之下, 我觉得现在技术换代很快,使用一项技术,首先是要快速的解决问题,然后要学习他的思想,那些整天死抱着Hibernate,自认为学习到ORM的设计技巧的人,就去继续的学吧。 我已经会用Hibernate的一些方面,我觉得够用就行了,犯不上,天天钻研HSQL,如果有时间,我觉得躺在草坪上看看Unix的编程艺术,看看代码大全,看看Oracle的编程艺术,比看Hibernate的SB书要惬意多了。 简单能够带来快乐,用过EJB,再用Spring的人,都有体会,那简直是一种思想上的重生。
声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
|
| 返回顶楼 | |
|
最后更新时间:2007-05-05
其实ORM(不特指Hibernate)在实际项目当中,设计和运用的比较好的话,在OLTP类型的应用当中,性能是肯定要远远超过SQL Map的(例如iBATIS),其根源在于ORM可以透明的插入对象级别的缓存,而SQL Map是做不到这么细颗粒度的缓存的。而当一个web类型的OLTP应用的数据量和用户量达到一个相当大的规模的时候,应用级别的缓存无疑最有效的性能提升手段,这个时候ORM的威力就体现出来了。
http://www.javaeye.com/topic/72578 关于这一点,在Gavin King上海交流研讨会上面我已经谈了这个话题。当然对于ORM的方面的理解,我自己也是一直到去年底才真正搞明白的。这多少也是因为使用了RoR的AR以后,对ORM的看法更加客观之后才能够得出来的。 当然,不得不说的是,Hibernate虽然是一个强大的ORM,却不是一个非常易用的ORM,鉴于大多数程序员的编程基础都不过硬,要求他们良好的运用Hibernate基本是不可能的。这个时候也许iBATIS会给他们更可靠的编程能力。 |
|
| 返回顶楼 | |
|
最后更新时间:2007-05-05
to robbin:
ORM, 我现只能看到关系映射与维护这一层,至于OLTP这种类型的应用,我也没有做这样的项目,所以看不到这么远。 不过在实际的应用中,有二级缓存,总比没有强,但作用多大,我实际上是讲不清楚的。因为在实际的调优过程中,这一项,一直是打开的,并且用的是TreeCache。但瓶颈点不在这个地方,所以感觉效果并不是很明显。也许去掉二级缓存,就能感觉到了。 |
|
| 返回顶楼 | |
|
最后更新时间:2007-05-05
另外,如果使用Hibernate,大部分的应用,对于延迟加载是必须要打开的,否则就玩不转了。
但打开延迟加载,一般都使用OpenSessionFilter.无论如何,在连接的保持的时间上,要延长一些。 在论坛当中有一个精华帖,说道了这个性能问题,对于一般的应用是没有关系的,无非是加上了response.write()的时间,这个时间对于不同的页面,视数据量不同,时间有长有短,不定。 但要不要在自己的应用当中使用OpenSessionFilter,对我而言觉得也是一个比较难的决策,如果你使用了,但在后期提交压力测试,通不过,再返工,就没有那么容易。因为如果不用这个Filter,代码就不是这样子写的。 |
|
| 返回顶楼 | |
|
最后更新时间:2007-05-05
OneEyeWolf 写道 to robbin:
ORM, 我现只能看到关系映射与维护这一层,至于OLTP这种类型的应用,我也没有做这样的项目,所以看不到这么远。 不过在实际的应用中,有二级缓存,总比没有强,但作用多大,我实际上是讲不清楚的。因为在实际的调优过程中,这一项,一直是打开的,并且用的是TreeCache。但瓶颈点不在这个地方,所以感觉效果并不是很明显。也许去掉二级缓存,就能感觉到了。 OLTP就是相对于OLAP来说的,联机事务处理,普通的不涉及到大数据量报表分析查询的系统其实都是OLTP,特别是一般的互联网网站都是OLTP。 二级缓存在数据量小访问量小的时候,效果看不出来,当然也需要程序员在开发的时候就要有针对性的设计。但是当数据量大的时候,效果就出来了。一般的程序员在软件交付使用以后,不再继续跟踪这个项目了,所以一般不会涉及到这个层面。因此无论是ORM运用不好造成的严重性能问题,还是Hibernate良好运用对于性能的巨大提升,一般都没有一个清楚的认识。他们只知道通过看到log里面一屏一屏滚过的SQL就觉得Hibernate有问题了,呵呵。 Hibernate的二级缓存是针对对象级别的,即使你打开TreeCache,如果你没有针对具体的对象设置cache选项,一样没有用上。另外就像我在演讲里面提到过的,用不用ORM,用不用缓存,这是一个架构问题,不单纯是你打开不打开TreeCache这么简单,而是涉及到你的整个数据库表结构应该怎么设计,对象关联怎么安排,查询语句怎么写的各方面问题了。 这其实是一个很大的话题,不展开谈了。反正我的观点还是那样,如果对ORM的理解不深刻,对整个架构设计掌控能力不到位的话,那么还是用iBATIS吧。 |
|
| 返回顶楼 | |
|
最后更新时间:2007-05-05
OneEyeWolf 写道 另外,如果使用Hibernate,大部分的应用,对于延迟加载是必须要打开的,否则就玩不转了。
但打开延迟加载,一般都使用OpenSessionFilter.无论如何,在连接的保持的时间上,要延长一些。 在论坛当中有一个精华帖,说道了这个性能问题,对于一般的应用是没有关系的,无非是加上了response.write()的时间,这个时间对于不同的页面,视数据量不同,时间有长有短,不定。 但要不要在自己的应用当中使用OpenSessionFilter,对我而言觉得也是一个比较难的决策,如果你使用了,但在后期提交压力测试,通不过,再返工,就没有那么容易。因为如果不用这个Filter,代码就不是这样子写的。 这到不是什么问题。OpenSessionInView造成的Session资源不能及时释放的问题,只会出现在互联网应用当中。对于企业内网应用,网络速度足够快,response.write()不会造成多少延时。即使在互联网网站当中,你只要在Tomcat前面放一个apache web server,隔离慢速网络连接和tomcat的response.write速度差异就行了,tomcat在把response body写入到操作系统的TCP buffer之后,就已经释放session了,然后apache会慢慢从buffer里面取数据通过慢速互联网连接flush给浏览器的。 |
|
| 返回顶楼 | |
|
最后更新时间:2007-05-05
我做的就是电子商务网站应用,对于性能是有一定要求的,上线前是必须要提交压力测试的,应用服务器用的是WS + apache, 但这个险我是不敢冒的。
我这种应用也算是OLTP的应用了,我看错了,以为Robbin说的是基于数据仓库和挖掘之类的应用了,不过我现在的网站应用,以及以前所做的管理系统,出的问题,都是出现在开发人员对Hibernate的特性掌握的不好,对于复杂的查询, 难以应对,就又回归到通过Hibernate写原生SQL的道路上。 所以我觉得,对于一般的应用,问题的瓶颈点,还不到这一级。 |
|
| 返回顶楼 | |
|
最后更新时间:2007-05-06
robbin 写道 OneEyeWolf 写道 to robbin:
ORM, 我现只能看到关系映射与维护这一层,至于OLTP这种类型的应用,我也没有做这样的项目,所以看不到这么远。 不过在实际的应用中,有二级缓存,总比没有强,但作用多大,我实际上是讲不清楚的。因为在实际的调优过程中,这一项,一直是打开的,并且用的是TreeCache。但瓶颈点不在这个地方,所以感觉效果并不是很明显。也许去掉二级缓存,就能感觉到了。 OLTP就是相对于OLAP来说的,联机事务处理,普通的不涉及到大数据量报表分析查询的系统其实都是OLTP,特别是一般的互联网网站都是OLTP。 二级缓存在数据量小访问量小的时候,效果看不出来,当然也需要程序员在开发的时候就要有针对性的设计。但是当数据量大的时候,效果就出来了。一般的程序员在软件交付使用以后,不再继续跟踪这个项目了,所以一般不会涉及到这个层面。因此无论是ORM运用不好造成的严重性能问题,还是Hibernate良好运用对于性能的巨大提升,一般都没有一个清楚的认识。他们只知道通过看到log里面一屏一屏滚过的SQL就觉得Hibernate有问题了,呵呵。 Hibernate的二级缓存是针对对象级别的,即使你打开TreeCache,如果你没有针对具体的对象设置cache选项,一样没有用上。另外就像我在演讲里面提到过的,用不用ORM,用不用缓存,这是一个架构问题,不单纯是你打开不打开TreeCache这么简单,而是涉及到你的整个数据库表结构应该怎么设计,对象关联怎么安排,查询语句怎么写的各方面问题了。 这其实是一个很大的话题,不展开谈了。反正我的观点还是那样,如果对ORM的理解不深刻,对整个架构设计掌控能力不到位的话,那么还是用iBATIS吧。 我同意Robbin的观点,不是所有的对象,都适合Cache的,也不能拿着Cache,当锤子,把所有的对象,都看成钉子。 如果一个对象频繁的在cache当中被换进换出,反而降低性能。 所以就需要分析,需要设计。将不变的,变动少的,和频繁更新的进行剥离。 但如果把调优的寄与Hibernate的二级缓存之上,也许太过于偏执。 比较能够改善性能的,还是全局缓存,然后才是二级缓存。 调优也是讲究次序的,关键是性能瓶颈点在什么地方。 如果要进一步的提高性能,可能是一些商业级的缓存产品,如TangoSol。 另外以前,有人说过Hibernate的二级缓存打开,在cluster环境下,有影响,这个具体我没有测试过,不知道是不是真的? |
|
| 返回顶楼 | |
|
最后更新时间:2007-05-06
最近也感觉ORM工具不好用,不过没有太多技术因素,主要是在互联网应用中,大量使用的是查询操作,感觉OO的意义并不明显。另外就是人员问题,无论是熟练级别还是精通级别,SQL比HQL容易找到人手。
|
|
| 返回顶楼 | |
|
最后更新时间:2007-06-06
引用 我同意Robbin的观点,不是所有的对象,都适合Cache的,也不能拿着Cache,当锤子,把所有的对象,都看成钉子。 如果一个对象频繁的在cache当中被换进换出,反而降低性能。 所以就需要分析,需要设计。将不变的,变动少的,和频繁更新的进行剥离。 但如果把调优的寄与Hibernate的二级缓存之上,也许太过于偏执。 比较能够改善性能的,还是全局缓存,然后才是二级缓存。 调优也是讲究次序的,关键是性能瓶颈点在什么地方。 这说明你并没有认识到对象缓存的真正作用。并不是说把什么调优寄予Hibernate的二级缓存之上,如果你的应用架构本来就不是针对ORM进行设计的,你再怎么使用二级缓存也没有效果。 缓存是有很多层次的,有web server前端缓存,有动态页面静态化,有页面片断缓存,有查询缓存,也有对象缓存。不同层面的缓存适用于不同的应用场景,作用也各自不同,如果可以,你全部一起用上,他们不矛盾,但这个话题比较大,现在不展开谈。 针对OLTP类型的web应用,只要代码写的质量没有问题,最终的性能瓶颈毫无疑问还是数据库查询。应用服务器层面可以水平扩展,但是数据库是单点的,很难水平扩展,所以如何有效降低数据库查询频率,减轻数据库压力,是web应用性能问题的根源。 以上所有的缓存方式都可以直接或者间接的降低数据库访问,但缓存是有应用场景的,虽然新闻网站非常适合使用动态页面静态化技术,但是例如电子商务网站就不适合动态页面静态化,而页面缓存和查询缓存可以使用的场景也不多。但是对象缓存是所有缓存技术当中适用场景最广泛的,任何OLTP应用,即使实时性要求很高,你也可以使用对象缓存,而且好的ORM实现,对象缓存是完全透明的,不需要你的程序代码进行硬编码。 用不用对象缓存,怎么用对象缓存,不是一个调优的技巧问题,而是整个应用的架构问题。在你开发一个应用之前,你就要想清楚,这个应用最终的场景是什么?会有多大的用户量和数据量。你将采用什么方式来架构这个应用: OK,也许你偏爱SQL,那么你选择iBATIS,数据库设计当中大表有很多冗余字段,会尽量消除大表之间的关联关系,最终用户量和访问量很高以后,你会选择使用Oracle,雇佣资深的DBA,进行数据库调优和SQL调优,这是大多数公司走的路。 但是我告诉你,你还有另外一条路可以走。你可以选择ORM(不见得一定是Hibernate),数据库设计当中避免出现大表,比较多的表关联关系,通过ORM以对象化方式操作。当用户量和访问量很高以后,除了数据库端本身的优化,你还有对象缓存这条途径。对象缓存是怎样提高性能的呢?随便举个例子: 论坛的列表页面,需要显示topic的分页列表,topic作者的名字,topic最后回复帖子的作者,如果是iBATIS,你准备怎么做? select ... from topic left join user left join post ..... 你需要通过join user表来取得topic作者的名字,然后你还需要join post表取得最后回复的帖子,post再join user表取得最后回贴作者名字。 也许你说,我可以设计表冗余,在topic里面增加username,在post里面增加username,所以通过大表冗余字段,消除了复杂的表关联: select ... from topic left join post... OK,且不说冗余字段的维护问题,现在仍然是两张大表的关联查询。然后让我们看看ORM怎么做? select * from topic where ... --分页条件 就这么一条SQL搞定,比上面的关联查询对数据库的压力小多了。 也许你说,不对阿,作者信息呢?回贴作者信息呢?这些难道不会发送SQL吗?如果发送SQL,这不就是臭名昭著的n+1条问题吗? 你说的对,最坏情况下,会有很多条SQL: select * from user where id = topic_id...; .... select * from user where id = topic_id...; select * from post where id = last_topic_id...; .... select * from post where id = last_topic_id...; select * from user where id = post_id...; .... select * from user where id = post_id...; 事实上何止n+1,根本就是3n+1条SQL了。那你怎么还说ORM性能高呢? 因为对象缓存在起作用,你可以观察到后面的3n条SQL语句全部都是基于主键的单表查询,这3n条语句在理想状况下(比较繁忙的web网站),全部都可以命中缓存。所以事实上只有一条SQL,就是: select * from topic where ...--分页条件 这条单表的条件查询和iBATIS通过字段冗余简化过后的大表关联查询相比,当数据量大到一定程度以后(十几万条),查询的速度会差至少一个数量级,而且对数据库的压力很小,这就是对象缓存的真正威力! 引用 如果要进一步的提高性能,可能是一些商业级的缓存产品,如TangoSol。
Hibernate二级缓存只是一个缓存接口,可以使用任意Java缓存产品,你完全可以用Tangosol做Hibernate的二级缓存。我还是那句话,如果你的应用不是针对ORM进行设计的,就算你用上Tangosol,也没什么用。 引用 另外以前,有人说过Hibernate的二级缓存打开,在cluster环境下,有影响,这个具体我没有测试过,不知道是不是真的?
那要看你用不用支持cluster的缓存产品了。如果在cluster环境下,你非要用一个不支持cluster的缓存产品,你说有没有问题? |
|
| 返回顶楼 | |






