`
robbin
  • 浏览: 4795372 次
  • 性别: Icon_minigender_1
  • 来自: 上海
博客专栏
377a9ecd-1ea1-34ac-9530-9daa53bb2a7b
robbin谈管理
浏览量:135471
社区版块
存档分类
最新评论

为什么ORM性能比iBATIS好?

    博客分类:
  • Java
阅读更多
缓存是有很多层次的,有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通过字段冗余简化过后的大表关联查询相比,当数据量大到一定程度以后(十几万条),查询的速度会差至少一个数量级,而且对数据库的压力很小,这就是对象缓存的真正威力!

更进一步分析,使用ORM,我们不考虑缓存的情况,那么就是3n+1条SQL。但是这3n+1条SQL的执行速度一定比iBATIS的大表关联查询慢吗?不一定!因为使用ORM的情况下,第一条SQL是单表的条件查询,在有索引的情况下,速度很快,后面的3n条SQL都是单表的主键查询,在繁忙的数据库系统当中,3n条SQL几乎可以全部命中数据库的data buffer。但是使用iBATIS的大表关联查询,很可能会造成全表扫描,这样性能是非常差的。

所以结论就是:即使不使用对象缓存,ORM的n+1条SQL性能仍然很有可能超过iBATIS的大表关联查询,而且对数据库造成的压力要小很多。这个结论貌似令人难以置信,但经过我的实践证明,就是事实。前提是数据量和访问量都要比较大,否则看不出来这种效果

还是拿上面这个例子的应用场景来说,由于JavaEye网站用RoR的ActiveRecord,所以这个场景事实上就会发送3n+1条SQL语句。我从log里面看到这密密麻麻的SQL,着实非常担忧性能,所以尝试使用了find的:include选项去eager fetch,迫使ActiveRecord发送单条复杂的关联查询。但非常不幸的是,在网站服务器的production.log里面经过前后对比,发现使用:include以后,单条复杂关联查询耗时更多,数据库压力更大。

在使用memcached之后,比3n+1条的性能进一步明显提升。所以性能对比就是这样的:

ORM + Cache > ORM n+1 > iBATIS 关联查询

那为什么应用Cache可以进一步提高性能,是因为访问Cache的开销比访问数据库小的得多造成的。

应用程序根据主键key去Cache Server取value,是非常简单的算法,开销极小。
而发送一条主键查询的SQL到数据库,要经过非常复杂的过程,有SQL的解析,执行计划的优化,占位符参数的代入,只读事务的保护和隔离等等,最终虽然也命中了数据库的data buffer,但是开销确实很大。

BerkeleyDB就是一个极好的证明,它号称其查询速度是Oracle的1000倍,不是因为它做的比Oracle牛,而是因为它本质上就是一个大Cache,查询没有额外的开销。
分享到:
评论
35 楼 cpjsjxy 2012-09-26  
这理论行得通吗?ibatis就不能缓存了吗?
34 楼 laiweiweihi 2011-08-23  
bei79 写道
同意wtusmchen的观点,同时感谢Robbin提出的这个议题, 这种话题向来是越辨越明的.

还有就是想弱弱的问下:
javaeye中是怎么做到每个用户有自已的访问域名的, 类似:
http://robbin.iteye.com
知道的不要笑话俺, 俺就是很感兴趣, 想知道一下. 先行谢过.

跟你的域名解析商家要二级域名解析,然后自己服务器上面做个泛型二级域名url重写。就完了。
33 楼 Arden 2011-08-11  
orm可以缓存,难道sql查询方案就不能有缓存方案了~sql查询你自己也可以做缓存啊~
32 楼 walle1027 2011-01-21  
实践出真知,大家贴出数据来,好好研究研究。
31 楼 ljy325 2008-12-26  
请列出测试证据!
理论分析合理,但需要数字说话.
30 楼 wuyou 2008-11-22  
如果在 查询时加上 with(nolock) ,嘿嘿,性能会提高很多,特别是并发情况

好象 hibernate 查询时 不好做 with(nolock) 吧, ibatis 应该不会有这种问题

论坛这种应用,查询可以设置很多的缓存以提高性能

但是如果是一些不能靠缓存提高性能的应用,还是要老老实实优化 sql 吧,这时候我想 ibaits 还是优于 hibernate 的

29 楼 SINCE1978 2008-11-14  
不错。另外个人认为n+1是一种现象而不是一种需要解决的问题:
我们一般规模的业务系统的缓存基本上可以肯定是不能100%依赖的,就是说如果我们的缓存是一份数据库数据的完全拷贝(增删改查数据库的同时维护缓存)那么可以100%依赖它,这相当于内存数据库了。但是如果缓存没有淘汰机制随业务数据量上升最后内存会溢出的,这肯定不行,所以缓存一般都有淘汰机制如lru(估计hibernate也有),这样我们的对象级别缓存能保证的是缓存有的对象数据库一定有记录,但是缓存没有的数据库不一定没有,所以说:我们可以在对象级别上50%的依赖缓存、在批量级别上无法依赖缓存(除非你保证你的缓存就是包含所有数据的内存数据库)

故:凡是涉及到批量的查询sql我们可以首先直接查询数据库满足条件的主键(如select id from .. where ...我不知这种批量查主键的方式是否效率有优化、想必有)、然后遍历主键、先去缓存找(以主键为键的缓存)、找不到去数据库找(必能找到)、返回应用同时放入缓存...这也符合lru算法模型,因为这是一次“命中”

写的很好,就是有点文不对题,致使争论,这不仅仅是orm、ibatis这些的问题。我一直有此疑惑,robbin的测试结果给我解了惑,谢谢。通用缓存想不出来用什么方式好做,哪位大侠推荐一下好的缓存框架?OSCache?EHCache?...
28 楼 tonik 2008-08-19  
thx
我也只是按照自己的想法说的
我自己也才做了几年的开发,经验明显不足
不对的地方,希望指正

ibatis确实可以缓存,只是确实不如hibernate一类简单
但是,从别的查询速度、灵活性上来说,也有自己的优势
而且,也有不少情况ibatis是比较好的选择
27 楼 robbin 2008-08-19  
to tonik:

DB端的缓存和应用层缓存是两码事。DB端用了缓存,并不意味着你应用层就不需要继续做缓存了。

iBATIS的查询颗粒度和ORM是不一样的。应用层缓存策略也有好几种,iBATIS只能做到查询缓存级别,做不到对象缓存级别。
26 楼 tonik 2008-08-19  

我看了这个人的几篇文章,说实话
我觉得他技术·····

反正对自己讨论这些东西认识还不够深
前天看了讨论jsf seam的,今天又看了这篇

就拿这篇来说,反正是执行数据库操作,要说缓存,也是db server的缓存
这篇文章里面BerkeleyDB,那也是db端的 和你说的orm根本不是一回事
根本上来讲,再怎么orm还不是要和数据库对应起来,你能不操作数据库?
就算是缓存一部分,查询一部分,也得查询
我用ibatis或者查询了再处理一下也行啊

25 楼 melin 2008-08-06  
引用
iBATIS一样也有缓存, hibernate能做到的 iBATIS其本上也能做到, 只是也许比较麻烦, 所以抓住一个缓存来打死iBATIS有点搞笑


Robbin是捅了马蜂窝。。。
24 楼 donyad 2008-07-29  
iBATIS一样也有缓存, hibernate能做到的 iBATIS其本上也能做到, 只是也许比较麻烦, 所以抓住一个缓存来打死iBATIS有点搞笑
23 楼 supttkl 2008-04-12  
受益匪浅,以前一直鄙视hibernate
22 楼 bei79 2008-02-21  
同意wtusmchen的观点,同时感谢Robbin提出的这个议题, 这种话题向来是越辨越明的.

还有就是想弱弱的问下:
javaeye中是怎么做到每个用户有自已的访问域名的, 类似:
http://robbin.iteye.com
知道的不要笑话俺, 俺就是很感兴趣, 想知道一下. 先行谢过.
21 楼 dimscar 2007-09-04  
我是从IBATIS到HIBERNATE的,我用到今天,二个各有各自的好处,IBATIS的CACHE也一样好用,也一样的简单,HIBERNATE也一样,至于二个比较嘛,不能说哪个比哪个好,只能说各自应用喽,淘宝还用IBATIS呢!
20 楼 javafanwind 2007-08-22  
ltian     2007-07-02 16:01
弱弱地问问.什么是OLTP类型的web应用?
OLTP
在线事务处理。。。
19 楼 element1999 2007-06-28  
  从文中举的例子来说明orm的效率高于ibatis,很难让人信服。
  首先需要肯定的是在高负荷,cache中命中率较高的情况下,orm效率高于ibatis并不奇怪。
  但是,如果orm没有缓存。依靠sql语句进行数据访问。那么效率的高低主要取决你sql调优的情况。并不是简单的left join而已。如果真的想用ibatis,需要较高的效率,那么我相信,找一个DBA调优数据库,写sql语句。没有缓存的orm和ibatis还是无法比拟的。

 
18 楼 systembug 2007-06-28  
ibatis也是ORM,只不过实现的方式是Sql Map。不知是使用什么ORM和ibatis进行比较。而且这个本就不具有可比性。
17 楼 drinkjava 2007-06-26  
换个例子吧,至少这个例子不合适,如果不用ORM,最高效的做法是在topic表中加入作者,最后回贴人,最后回贴时间,回贴总数等冗余数据,把复杂性转移到业务逻辑代码中,这样一个SQL就解决了: select * from topic,并不是如作者所说一定要作left join查询。
16 楼 X.D.Hua 2007-06-26  
我觉得这篇文章无疑对我帮助很大,看来技术留给我还有很大的思考空间,很感谢robbin,希望以后还能看到这样的文章。

相关推荐

    ibatis 开发指南

    相对Hibernate等 “全自动”ORM机制而言,ibatis 以SQL开发的工作量和数据库移植性上的让步,为系统 设计提供了更大的自由空间。作为“全自动”ORM 实现的一种有益补充,ibatis 的出现显 得别具意义。

    iBATIS技术教程PPT和代码.rar

    iBATIS是一种“半自动化”的ORM实现。 所谓“半自动”,可能理解上有点生涩。纵观目前主流的 ORM,无论 Hibernate 还是Apache OJB,都对数据库结构提供了较为完整的封装,提供了从 POJO 到数据库表的全套映射机制。...

    ibatis教程

    iBatis是一个简单易用的、灵活的Java ORM工具包,iBatis执行效率非常高,接近于JDBC的代码的效率,因此iBatis适合做对数据性能要求很高的应用系统。 iBatis目前的最新版本是3.02,最稳定的版本是2.3.4,由于iBatis的...

    ibatis 开发指南(pdf)

    相对Hibernate 等 “全自动”ORM 机制而言,ibatis 以SQL 开发的工作量和数据库移植性上的让步,为系统 设计提供了更大的自由空间。作为“全自动”ORM 实现的一种有益补充,ibatis 的出现显 得别具意义。...

    mybatis_day01.docx

    mybatis是一种持久层框架,也属于ORM映射。前身是ibatis。 相比于hibernatehibernate为全自动化,配置文件书写之后不需要书写sql语句,但是欠缺灵活,很多时候需要优化; mybatis为半自动化,需要自己书写sql语句,...

    最新Java面试宝典pdf版

    为什么? 9 8、用最有效率的方法算出2乘以8等於几? 9 9、请设计一个一百亿的计算器 9 10、使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变? 11 11、"=="和equals方法究竟有什么区别? 11 12、...

    Java面试宝典2010版

    为什么? 8、用最有效率的方法算出2乘以8等於几? 9、请设计一个一百亿的计算器 10、使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变? 11、"=="和equals方法究竟有什么区别? 12、静态变量和...

    Java面试笔试资料大全

    为什么? 9 8、用最有效率的方法算出2乘以8等於几? 9 9、请设计一个一百亿的计算器 9 10、使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变? 11 11、"=="和equals方法究竟有什么区别? 11 12、...

    java面试题大全(2012版)

    为什么? 9 8、用最有效率的方法算出2乘以8等於几? 9 9、请设计一个一百亿的计算器 9 10、使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变? 11 11、"=="和equals方法究竟有什么区别? 11 12、...

    Java面试宝典2012版

    为什么? 9 8、用最有效率的方法算出2乘以8等於几? 9 9、请设计一个一百亿的计算器 9 10、使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变? 11 11、"=="和equals方法究竟有什么区别? 11 ...

    JAVA面试宝典2010

    为什么? 9 8、用最有效率的方法算出2乘以8等於几? 9 9、请设计一个一百亿的计算器 9 10、使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变? 11 11、"=="和equals方法究竟有什么区别? 11 12、...

    java面试宝典2012

    为什么? 9 8、用最有效率的方法算出2乘以8等於几? 10 9、请设计一个一百亿的计算器 10 10、使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变? 11 11、"=="和equals方法究竟有什么区别? 12 12、...

    Java面试宝典2012新版

    为什么? 9 8、用最有效率的方法算出2乘以8等於几? 9 9、请设计一个一百亿的计算器 9 10、使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变? 11 11、"=="和equals方法究竟有什么区别? 11 12、...

    Java面试宝典-经典

    为什么? 9 8、用最有效率的方法算出2乘以8等於几? 9 9、请设计一个一百亿的计算器 9 10、使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变? 11 11、"=="和equals方法究竟有什么区别? 11 12、...

    hibernate与mybatis一起使用取长补短

    一个项目中同时使用hibernate和ibatis两个orm框架,既利用到了hibernate的强大功能也弥补到了hibernate对大数据操作的性能上的影响

    guzz开发jar

    guzz是一套用来进行快速开发和高性能网站设计的java框架,通过ORM、多数据源数据管理、以及通用数据处理,为系统在数据层的设计提供一站式解决方案。用于替代或者补充hibernate或ibatis,并提供更多的大型系统架构...

    最新Java面试题视频网盘,Java面试题84集、java面试专属及面试必问课程

    │ Java面试题56.ibatis和hibernate有什么不同.mp4 │ Java面试题57.hibernate对象状态及其转换.mp4 │ Java面试题58:hibernate的缓存.mp4 │ Java面试题59.webservice的使用场景.mp4 │ Java面试题60.Activiti的...

    springmybatis

    性能也比hibernate好。而且也比较轻量级,因为当时在项目中,没来的及做很很多笔记。后来项目结束了,我也没写总结文档。已经过去好久了。但最近突然又对这个ORM 工具感兴趣。因为接下来自己的项目中很有可能采用这...

Global site tag (gtag.js) - Google Analytics