缓存是有很多层次的,有web server前端缓存,有动态页面静态化,有页面片断缓存,有查询缓存,也有对象缓存。不同层面的缓存适用于不同的应用场景,作用也各自不同,如果可以,你全部一起用上,他们不矛盾,但这个话题比较大,现在不展开谈。
针对OLTP类型的web应用,只要代码写的质量没有问题,最终的性能瓶颈毫无疑问还是数据库查询。应用服务器层面可以水平扩展,但是数据库是单点的,很难水平扩展,所以如何有效降低数据库查询频率,减轻数据库压力,是web应用性能问题的根源。
以上所有的缓存方式都可以直接或者间接的降低数据库访问,但缓存是有应用场景的,虽然新闻网站非常适合使用动态页面静态化技术,但是例如电子商务网站就不适合动态页面静态化,而页面缓存和查询缓存可以使用的场景也不多。但是对象缓存是所有缓存技术当中适用场景最广泛的,任何OLTP应用,即使实时性要求很高,你也可以使用对象缓存,而且好的ORM实现,对象缓存是完全透明的,不需要你的程序代码进行硬编码。
用不用对象缓存,怎么用对象缓存,不是一个调优的技巧问题,而是整个应用的架构问题。在你开发一个应用之前,你就要想清楚,这个应用最终的场景是什么?会有多大的用户量和数据量。你将采用什么方式来架构这个应用:
OK,也许你偏爱SQL,那么你选择iBATIS,数据库设计当中大表有很多冗余字段,会尽量消除大表之间的关联关系,最终用户量和访问量很高以后,你会选择使用Oracle,雇佣资深的DBA,进行数据库调优和SQL调优,这是大多数公司走的路。
但是我告诉你,你还有另外一条路可以走。你可以选择ORM(不见得一定是Hibernate),数据库设计当中避免出现大表,比较多的表关联关系,通过ORM以对象化方式操作。当用户量和访问量很高以后,除了数据库端本身的优化,你还有对象缓存这条途径。对象缓存是怎样提高性能的呢?随便举个例子:
论坛的列表页面,需要显示topic的分页列表,topic作者的名字,topic最后回复帖子的作者,如果是iBATIS,你准备怎么做?
Sql代码
select ... from topic left join user left join post .....
select ... from topic left join user left join post .....
你需要通过join user表来取得topic作者的名字,然后你还需要join post表取得最后回复的帖子,post再join user表取得最后回贴作者名字。
也许你说,我可以设计表冗余,在topic里面增加username,在post里面增加username,所以通过大表冗余字段,消除了复杂的表关联:
Sql代码
select ... from topic left join post...
select ... from topic left join post...
OK,且不说冗余字段的维护问题,现在仍然是两张大表的关联查询。然后让我们看看ORM怎么做?
Sql代码
select * from topic where ... --分页条件
select * from topic where ... --分页条件
就这么一条SQL搞定,比上面的关联查询对数据库的压力小多了。
也许你说,不对阿,作者信息呢?回贴作者信息呢?这些难道不会发送SQL吗?如果发送SQL,这不就是臭名昭著的n+1条问题吗?
你说的对,最坏情况下,会有很多条SQL:
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...;
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,就是:
Sql代码
select * from topic where ...--分页条件
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,查询没有额外的开销。
分享到:
相关推荐
通过使用iBatis,开发者可以享受到ORM带来的便利,同时避免了完全自动化ORM框架可能导致的性能损失和灵活性下降。半自动化的ORM映射方式让开发者在控制和便捷之间找到了一个良好的平衡点。在实践中,根据项目需求和...
### iBATIS ORM指南知识点详解 #### 一、iBATIS简介 iBATIS 是一个开源框架,用于简化 Java 应用程序与数据库之间的交互。它通过提供 SQL 映射功能来实现这一目标,允许开发者将 Java 对象映射到数据库表中的记录...
iBatisDemo示例项目是基于iBatis.Net框架的一个应用实例,该框架是一个轻量级的ORM(Object-Relational Mapping,对象关系映射)解决方案。ORM的主要目的是通过将数据库操作与业务逻辑代码分离,使得开发人员可以...
4. **更好的数据库性能**:由于iBatis允许直接编写SQL,开发者可以优化SQL以提升数据库性能。 **整合Hibernate和iBatis** 整合Hibernate和iBatis,主要是利用Hibernate的ORM能力和iBatis的SQL灵活性。一种常见的...
《ibatis开发指南》经典教材深入讲解了ibatis框架的核心概念和高级应用,为开发者提供了全面的指导。ibatis,作为一款“半自动化”的对象关系映射(Object-Relational Mapping,简称ORM)工具,其设计理念与传统的...
在Java世界中,iBATIS与Hibernate都是广泛应用的ORM解决方案,而根据描述,iBATIS被推崇为比Hibernate更好用,主要是因为它的SQL灵活性和对复杂查询的支持。 iBATIS的核心在于它的SQL Maps,这是一种XML或者注解...
4. 维护性:由于iBATIS的SQL存储在独立的XML文件中,相较于Hibernate在Java代码中混合SQL的情况,其可维护性更好。 四、iBATIS的工作流程 1. 接收对象参数,用于设置更新语句的输入值或查询语句的WHERE子句条件。 2...
3. 高效性能:由于不进行全自动的对象映射,iBatis在性能上通常优于全ORM框架。 三、iBatis的基本结构 iBatis主要包括以下组件: - SqlSessionFactoryBuilder:用于构建SqlSessionFactory。 - SqlSessionFactory:...
#### 1.1 什么是iBatis? iBatis是一个半自动的ORM框架,这意味着它不会完全抽象数据库的操作,而是提供了一种将Java对象与SQL语句之间进行映射的方式。这使得开发者能够更加灵活地控制SQL语句的生成,同时也保持了...
iBatis作为一种“半自动化”的ORM实现,为开发人员提供了一种在保持SQL灵活性的同时简化对象映射的方式。相较于全自动化ORM工具(如Hibernate),iBatis更适合于那些需要精细控制SQL语句或在已有系统基础上进行开发...
### 一、什么是ibatis? ibatis是一种开源的持久层框架,主要用于在Java应用程序中简化数据库访问操作。它提供了一种灵活的方式来执行SQL语句,并将结果集映射到Java对象。与Hibernate等其他ORM框架相比,ibatis更...
iBatis作为Java开发中的一个流行工具,它允许开发者将SQL语句直接写在配置文件中,提供了比传统ORM框架如Hibernate更高的灵活性,但同时也增加了手动维护的负担。 ORM框架的主要目标是简化数据库操作,通过将数据库...
Ibatis 是一款优秀的Java持久层框架,它与Hibernate和JPA等ORM框架不同,Ibatis 提供了更为灵活的SQL映射机制,允许开发者直接编写SQL语句,从而更好地控制查询过程,提高性能。在本资源"ibatis2.3.4.rar"中,包含了...
ibatis的“半自动化”特性使其在需要精细控制SQL语句、高安全性要求或高性能场景下展现出独特优势,成为Java开发人员在ORM领域的又一有力工具。通过上述知识点的梳理,我们不仅了解了ibatis的基本概念和操作流程,也...
5. **性能优势**:ibatis通常被认为比其他ORM框架性能更高,因为它允许开发者直接控制SQL语句的生成。 #### 二、Hibernate简介 Hibernate同样是一种持久化框架,但它采用了更高级的对象关系映射(ORM)策略。...
- **轻量级**:相比其他 ORM 框架,iBATIS 更加轻量级,资源占用少,对于资源敏感的应用程序来说是个很好的选择。 #### 快速入门 - **准备工作**:在开始使用 iBATIS 之前,需要安装 Java 环境,并确保已经下载了 ...
总结来说,Ibatis是一个实用的持久层框架,它提供了灵活的SQL操作和高效的映射机制,使得开发者可以更好地管理和控制数据库操作,提高了代码的可读性和可维护性。对于Java开发者来说,掌握Ibatis的基本知识是提升...