﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-faith-随笔分类-ORM_Hibernate</title><link>http://www.blogjava.net/day/category/20646.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 16 Mar 2007 09:13:21 GMT</lastBuildDate><pubDate>Fri, 16 Mar 2007 09:13:21 GMT</pubDate><ttl>60</ttl><item><title>Hibernate程序性能优化的考虑要点(转贴) </title><link>http://www.blogjava.net/day/archive/2007/03/14/103869.html</link><dc:creator>daty</dc:creator><author>daty</author><pubDate>Wed, 14 Mar 2007 11:43:00 GMT</pubDate><guid>http://www.blogjava.net/day/archive/2007/03/14/103869.html</guid><wfw:comment>http://www.blogjava.net/day/comments/103869.html</wfw:comment><comments>http://www.blogjava.net/day/archive/2007/03/14/103869.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/day/comments/commentRss/103869.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/day/services/trackbacks/103869.html</trackback:ping><description><![CDATA[
		<a href="/chunkyo/archive/2007/03/05/101894.html">http://www.blogjava.net/chunkyo/archive/2007/03/05/101894.html</a>
		<br />
		<br />本文依照HIBERNATE帮助文档，一些网络书籍及项目经验整理而成，只提供要点和思路，具体做法可以留言探讨，或是找一些更详细更有针对性的资料。 
<p>　　初用HIBERNATE的人也许都遇到过性能问题，实现同一功能，用HIBERNATE与用JDBC性能相差十几倍很正常，如果不及早调整，很可能影响整个项目的进度。</p><p>　　大体上，对于HIBERNATE性能调优的主要考虑点如下:</p><p>　　Ø 数据库设计调整</p><p>　　Ø HQL优化</p><p>　　Ø API的正确使用(如根据不同的业务类型选用不同的集合及查询API)</p><p>　　Ø 主配置参数(日志，查询缓存，fetch_size, batch_size等)</p><p>　　Ø 映射文件优化(ID生成策略，二级缓存，延迟加载，关联优化)</p><p>　　Ø 一级缓存的管理</p><p>　　Ø 针对二级缓存，还有许多特有的策略</p><p>　　Ø 事务控制策略。</p><p>　　1、 数据库设计</p><p>　　a) 降低关联的复杂性</p><p>　　b) 尽量不使用联合主键</p><p>　　c) ID的生成机制，不同的数据库所提供的机制并不完全一样</p><p>　　d) 适当的冗余数据，不过分追求高范式</p><p>　　2、 HQL优化</p><p>　　HQL如果抛开它同HIBERNATE本身一些缓存机制的关联，HQL的优化技巧同普通的SQL优化技巧一样，可以很容易在网上找到一些经验之谈。</p><p>　　3、 主配置</p><p>　　a) 查询缓存，同下面讲的缓存不太一样，它是针对HQL语句的缓存，即完全一样的语句再次执行时可以利用缓存数据。但是，查询缓存在一个交易系统(数据变更频繁，查询条件相同的机率并不大)中可能会起反作用:它会白白耗费大量的系统资源但却难以派上用场。</p><p>　　b) fetch_size，同JDBC的相关参数作用类似，参数并不是越大越好，而应根据业务特征去设置</p><p>　　c) batch_size同上。</p><p>　　d) 生产系统中，切记要关掉SQL语句打印。</p><p>　　4、 缓存</p><p>　　a) 数据库级缓存:这级缓存是最高效和安全的，但不同的数据库可管理的层次并不一样，比如，在ORACLE中，可以在建表时指定将整个表置于缓存当中。</p><p>　　b) SESSION缓存:在一个HIBERNATE SESSION有效，这级缓存的可干预性不强，大多于HIBERNATE自动管理，但它提供清除缓存的方法，这在大批量增加/更新操作是有效的。比如，同时增加十万条记录，按常规方式进行，很可能会发现OutofMemeroy的异常，这时可能需要手动清除这一级缓存:Session.evict以及Session.clear</p><p>　　c) 应用缓存:在一个SESSIONFACTORY中有效，因此也是优化的重中之重，因此，各类策略也考虑的较多，在将数据放入这一级缓存之前，需要考虑一些前提条件:</p><p>　　i. 数据不会被第三方修改(比如，是否有另一个应用也在修改这些数据?)</p><p>　　ii. 数据不会太大</p><p>　　iii. 数据不会频繁更新(否则使用CACHE可能适得其反)</p><p>　　iv. 数据会被频繁查询</p><p>　　v. 数据不是关键数据(如涉及钱，安全等方面的问题)。</p><p>　　缓存有几种形式，可以在映射文件中配置:read-only(只读，适用于很少变更的静态数据/历史数据)，nonstrict-read-write，read-write(比较普遍的形式，效率一般)，transactional(JTA中，且支持的缓存产品较少)</p><p>　　d) 分布式缓存:同c)的配置一样，只是缓存产品的选用不同，在目前的HIBERNATE中可供选择的不多，oscache, jboss cache，目前的大多数项目，对它们的用于集群的使用(特别是关键交易系统)都持保守态度。在集群环境中，只利用数据库级的缓存是最安全的。</p><p>　　5、 延迟加载</p><p>　　a) 实体延迟加载:通过使用动态代理实现</p><p>　　b) 集合延迟加载:通过实现自有的SET/LIST，HIBERNATE提供了这方面的支持</p><p>　　c) 属性延迟加载:</p><p>　　6、 方法选用</p><p>　　a) 完成同样一件事，HIBERNATE提供了可供选择的一些方式，但具体使用什么方式，可能用性能/代码都会有影响。显示，一次返回十万条记录(List/Set/Bag/Map等)进行处理，很可能导致内存不够的问题，而如果用基于游标(ScrollableResults)或Iterator的结果集，则不存在这样的问题。</p><p>　　b) Session的load/get方法，前者会使用二级缓存，而后者则不使用。</p><p>　　c) Query和list/iterator，如果去仔细研究一下它们，你可能会发现很多有意思的情况，二者主要区别(如果使用了Spring，在HibernateTemplate中对应find,iterator方法):</p><p>　　i. list只能利用查询缓存(但在交易系统中查询缓存作用不大)，无法利用二级缓存中的单个实体，但list查出的对象会写入二级缓存，但它一般只生成较少的执行SQL语句，很多情况就是一条(无关联)。</p><p>　　ii. iterator则可以利用二级缓存，对于一条查询语句，它会先从数据库中找出所有符合条件的记录的ID，再通过ID去缓存找，对于缓存中没有的记录，再构造语句从数据库中查出，因此很容易知道，如果缓存中没有任何符合条件的记录，使用iterator会产生N+1条SQL语句(N为符合条件的记录数)</p><p>　　iii. 通过iterator，配合缓存管理API，在海量数据查询中可以很好的解决内存问题，如:</p><p>　　while(it.hasNext()){</p><p>　　YouObject object = (YouObject)it.next();</p><p>　　session.evict(youObject);</p><p>　　sessionFactory.evice(YouObject.class, youObject.getId());</p><p>　　}</p><p>　　如果用list方法，很可能就出OutofMemory错误了。</p><p>　　iv. 通过上面的说明，我想你应该知道如何去使用这两个方法了。</p><p>　　7、 集合的选用</p><p>　　在HIBERNATE 3.1文档的“19.5. Understanding Collection performance”中有详细的说明。</p><p>　　8、 事务控制</p><p>　　事务方面对性能有影响的主要包括:事务方式的选用，事务隔离级别以及锁的选用</p><p>　　a) 事务方式选用:如果不涉及多个事务管理器事务的话，不需要使用JTA，只有JDBC的事务控制就可以。</p><p>　　b) 事务隔离级别:参见标准的SQL事务隔离级别</p><p>　　c) 锁的选用:悲观锁(一般由具体的事务管理器实现)，对于长事务效率低，但安全。乐观锁(一般在应用级别实现)，如在HIBERNATE中可以定义VERSION字段，显然，如果有多个应用操作数据，且这些应用不是用同一种乐观锁机制，则乐观锁会失效。因此，针对不同的数据应有不同的策略，同前面许多情况一样，很多时候我们是在效率与安全/准确性上找一个平衡点，无论如何，优化都不是一个纯技术的问题，你应该对你的应用和业务特征有足够的了解。</p><p>　　9、 批量操作</p><p>　　即使是使用JDBC，在进行大批数据更新时，BATCH与不使用BATCH有效率上也有很大的差别。我们可以通过设置batch_size来让其支持批量操作。</p><p>　　举个例子，要批量删除某表中的对象，如“delete Account”，打出来的语句，会发现HIBERNATE找出了所有ACCOUNT的ID，再进行删除，这主要是为了维护二级缓存，这样效率肯定高不了，在后续的版本中增加了bulk delete/update，但这也无法解决缓存的维护问题。也就是说，由于有了二级缓存的维护问题，HIBERNATE的批量操作效率并不尽如人意!</p><p>　　从前面许多要点可以看出，很多时候我们是在效率与安全/准确性上找一个平衡点，无论如何，优化都不是一个纯技术的问题，你应该对你的应用和业务特征有足够的了解，一般的，优化方案应在架构设计期就基本确定，否则可能导致没必要的返工，致使项目延期，而作为架构师和项目经理，还要面对开发人员可能的抱怨，必竟，我们对用户需求更改的控制力不大，但技术/架构风险是应该在初期意识到并制定好相关的对策。</p><p>　　还有一点要注意，应用层的缓存只是锦上添花，永远不要把它当救命稻草，应用的根基(数据库设计，算法，高效的操作语句，恰当API的选择等)才是最重要的。</p><img src ="http://www.blogjava.net/day/aggbug/103869.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/day/" target="_blank">daty</a> 2007-03-14 19:43 <a href="http://www.blogjava.net/day/archive/2007/03/14/103869.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>