加速你的Hibernate引擎(下) - 编程入门网
HRD中的第20章“改善性能”对该主题作了很好的阐述,我们在此将关注它的使用方法。
4.7.1覆盖抓取策略 不同的用户可能会有不同的数据抓取要求。Hibernate允许在两个地方定义数据抓取策略,一处是在映射元数据中,另一处是在HQL或Criteria中覆盖它。 常见的做法是基于主要的抓取用例在映射元数据中定义默认抓取策略,针对少数用例在HQL和Criteria中覆盖抓取策略。 假设pojoA和pojoB是父子关系实例。如果根据业务规则,只是偶尔需要从实体两端加载数据,那你可以声明一个延迟加载集合或代理抓取(proxy fetching)。当你需要从实体两端获取数据时,可以用立即抓取(eager fetching)覆盖默认策略,例如使用HQL或Criteria配置连接抓取(join fetching)。 另一方面,如果业务规则在大多数时候需要从实体两端加载数据,那么你可以声明立即抓取并在Criteria中设置延迟加载集合或代理抓取来覆盖它(HQL目前还不支持这样的覆盖)。 4.7.2 N+1模式或是反模式? select抓取会导致N+1问题。如果你知道自己总是需要从关联中加载数据,那么就该始终使用连接抓取。在下面两个场景中,你可能会把N+1视为一种模式而非反模式。 第一种场景,你不知道用户是否会访问关联对象。如果他/她没有访问,那么你赢了;否则你仍然需要额外的N次select SQL语句。这是一种令人左右为难的局面。 第二种场景,pojoA和很多其他POJO有one-to-many关联,例如pojoB和pojoC。使用立即的内连接或外连接抓取会在结果集中将pojoA重复很多次。当pojoA中有很多非空属性时,你不得不将大量数据加载到持久层中。这种加载需要很多时间,既有网络带宽的原因,如果 Hibernate的会话是有状态的,其中也会有会话缓存的原因(内存消耗和GC暂停)。 如果你有一个很长的one-to-many关联链,例如从pojoA到pojoB到pojoC以此类推,情况也是类似的。 你也许会去使用HQL中的DISTINCT关键字或Cirteria中的distinct功能或是Java的Set接口来消除重复数据。但所有这些都是在Hibernate(在持久层)中实现的,而非数据库中。 如果基于你的网络和内存配置的测试表明N+1性能更好,那么你可以使用批量抓取、subselect抓取或二级缓存来做进一步调优。 加速你的Hibernate引擎(下)(3)时间:2010-12-30 infoq 译:丁雪丰范例8 以下是一个使用批量抓取的HBM文件片段:
select … from pojoB where pojoa_id in(?,?,?,?,?, ?,?,?,?,?);问号数量与batch-size值相等。因此N次额外的关于pojoB的select SQL语句被减少到了N/10次。 如果将fetch="select"替换成fetch="subselect",pojoB生成的SQL语句就是这样的: select … from pojoB where pojoa_id in(select id from pojoA where …); 尽管N次额外的select减少到1次,但这只在重复运行pojoA的查询开销很低时才有好处。 如果pojoA中的pojoB集合很稳定,或pojoB有pojoA的many-to-one关联,而且pojoA是只读引用数据,那么你可以使用二级缓存来缓存pojoA以消除N+1问题(4.8.1节中有一个例子)。 4.7.3延迟属性抓取 除非有一张拥有很多你不需要的字段的遗留表,否则不应该使用这种抓取策略,因为它的延迟属性分组会带来额外的SQL。 在业务分析和设计过程中,你应该将不同数据获取或修改分组放到不同的领域对象实体中,而不是使用这种抓取策略。 如果不能重新设计遗留表,可以使用HQL或Criteria提供的投影功 |
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |