当前位置:  开发笔记 > 编程语言 > 正文

Hibernate可以用于性能敏感的应用程序吗?

如何解决《Hibernate可以用于性能敏感的应用程序吗?》经验,为你挑选了2个好方法。

我发现检索与其他对象有很多关系的多个对象实例时出现性能问题.我在MySQL中使用Spring和Hibernate的JPA实现.问题是,在执行JPA查询时,Hibernate不会自动连接到其他表.这导致n*r + 1个SQL查询,其中n是要检索的对象的数量,r是关系的数量.

例如,一个人住在一个​​地址,有很多爱好,并访问了许多国家:

@Entity
public class Person {
    @Id public Integer personId;    
    public String name;    
    @ManyToOne public Address address;    
    @ManyToMany public Set hobbies;    
    @ManyToMany public Set countriesVisited;
}

当我执行JPA查询以获取名为Bob的所有人员时,数据库中有100个Bobs:

SELECT p FROM Person p WHERE p.name='Bob'

Hibernate将此转换为301个SQL查询:

SELECT ... FROM Person WHERE name='Bob'
SELECT ... FROM Address WHERE personId=1
SELECT ... FROM Address WHERE personId=2
...
SELECT ... FROM Hobby WHERE personId=1
SELECT ... FROM Hobby WHERE personId=2
...
SELECT ... FROM Country WHERE personId=1
SELECT ... FROM Country WHERE personId=2
...

根据Hibernate FAQ(此处和此处),解决方案是在查询中指定LEFT JOIN或LEFT OUTER JOIN(对多对多).所以现在我的查询看起来像:

SELECT p, a, h, c FROM Person p
LEFT JOIN p.address a LEFT OUTER JOIN p.hobbies h LEFT OUTER JOIN p.countriesVisited c
WHERE p.name = 'Bob'

这有效,但是如果有多个LEFT OUTER JOIN似乎存在错误,在这种情况下Hibernate错误地寻找不存在的列:

could not read column value from result set: personId69_2_; Column 'personId69_2_' not found.

Hibernate Core bug HHH-3636可能会解决bug行为.不幸的是,修复程序不是任何已发布的Hibernate JAR的一部分.我已经针对快照构建运行了我的应用程序,但bug行为仍然存在.我还从存储库中的最新代码构建了自己的Hibernate Core JAR,并且仍然存在bug行为.所以也许HHH-3636没有解决这个问题.

这种Hibernate性能限制非常令人沮丧.如果我查询1000个对象,则对数据库进行1000*r + 1个SQL查询.在我的情况下,我有8个关系,所以我得到8001 SQL查询,这导致可怕的性能.官方的Hibernate解决方案就是将所有关系都加入.但由于bug行为导致多个多对多关系不可能实现这一点.因此,由于多对多关系,我因左对联而陷入多对一关系和n*r + 1查询.我计划将LEFT OUTER JOIN问题作为Hibernate错误提交,但与此同时我的客户需要一个具有合理性能的应用程序.我目前使用批量提取(BatchSize)的组合,ehcache和自定义内存缓存,但性能仍然很差(它改进了从30到8秒检索5000个对象).底线是太多的SQL查询正在访问数据库.

那么,我的问题是,是否可以在性能敏感的应用程序中使用Hibernate,其中表之间存在多种关系?我很想知道Hibernate如何成功使用地址性能.我应该亲自编写SQL(这有点违背了使用Hibernate的目的)?我应该取消规范化我的数据库架构以减少连接表的数量吗?如果我需要快速查询性能,我应该不使用Hibernate吗?有更快的东西吗?



1> toolkit..:

如果您阅读了链接到的所有常见问题解答,请参阅我对您的其他问题的回答:

遵循最佳实践指南!确保all和mappings在Hibernate2中指定lazy ="true"(这是Hibernate3中的新默认值).使用HQL LEFT JOIN FETCH指定在初始SQL SELECT中需要检索哪些关联.

避免n + 1选择问题的第二种方法是在Hibernate3中使用fetch ="subselect".

如果您仍然不确定,请参阅Hibernate文档和Hibernate in Action.

请参阅有关提高性能的提示.如果您对连接不小心,最终会遇到笛卡尔积问题.



2> serg..:

除了"获取"策略之外,您还可以尝试在hibernate属性中设置批量提取大小,因此它将逐个运行加入查询但是批量运行.

在appContext.xml中:


    ...    
    
                
            ...
            32
        
    

所以代替:

SELECT ... FROM Hobby WHERE personId=1
SELECT ... FROM Hobby WHERE personId=2

你会得到:

SELECT ... FROM Hobby WHERE personId in (1,2,...,32);
SELECT ... FROM Hobby WHERE personId in (33,34,...,64);

推荐阅读
农大军乐团_697
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有