提高JPA性能双向映射“n + 1 select”

时间:2015-10-15 10:11:08

标签: hibernate jpa eclipselink spring-data-jpa

我有两个实体Group和Person,我使用双向映射,在这种情况下我有n + 1个查询而不是一个。

public class Person extends BaseBean {
Group group ;
//getter and setter
}
public class Groupextends BaseBean {
List<Person>  childPersons;
//getter and setter
}

我使用eclipselink进行映射。

<entity name="person" class="tn.waycon.alquasar2.gp.model.Person">
        <attributes>
            <many-to-one name="group" fetch="EAGER">
                <join-column name="group_id" />
            </many-to-one>
        </attributes>
    </entity>

<entity name="group_of_persons" class="tn.waycon.alquasar2.gp.model.Group">
        <attributes>    
            <one-to-many name="childPersons" mapped-by="group" fetch="EAGER">
                <join-fetch>OUTER</join-fetch> 
                <cascade>
                    <cascade-all />
                </cascade>
            </one-to-many>  
        </attributes>

    </entity>

我使用spring数据jpa来获取数据。

@Query("select p from person p left join fetch p.group")
 List<Person> getAll();

问题是,当我选择人员列表时,getAll函数生成1个查询以选择所有人和n查询以获取所有Person by group_id。 这是getAll()函数生成的日志:

SELECT t1.ID,t1.activity,t1.last_name,t1.matricule,t0.NAME,t0.parent_id FROM PERSON t1 LEFT OUTER JOIN GROUP_OF_PERSONS t0 ON(t0.ID = t1.group_id)

Thread(Thread [main,5,main]) - SELECT ID,employ_date,first_name,gender,last_name,matricule,phone_number,title,group_id FROM PERSON WHERE(group_id =?) bind =&gt; [5302]

Thread(Thread [main,5,main]) - SELECT ID,employ_date,first_name,gender,last_name,matricule,phone_number,title,group_id FROM PERSON WHERE(group_id =?)     bind =&gt; [6965]

Thread(Thread [main,5,main]) - SELECT ID,employ_date,first_name,gender,last_name,matricule,phone_number,title,group_id FROM PERSON WHERE(group_id =?)     bind =&gt; [6980]

Thread(Thread [main,5,main]) - SELECT ID,employ_date,first_name,gender,last_name,matricule,phone_number,title,group_id FROM PERSON WHERE(group_id =?)

2 个答案:

答案 0 :(得分:1)

问题出在您的Person-&gt; Group关系上。它被标记为渴望并且没有任何提取选项,强制为从初始查询读入的每个Person单独查询。如上所述,将查询标记为使用加入或批量提取,或者使用与Group-&gt; Person关系相同或类似的OUTER选项将所有选项全部提取到单个查询中。

更好的是,除非你真的需要在应用程序的每个部分中获取关系,否则请保持懒惰。

答案 1 :(得分:0)

您在查询中使用了抓取功能(包括父级Person实体的&#39; group&#39;子元素)。这是预期的行为,因此您将遇到常见的N + 1 SQL SELECT问题。但是,由于您使用EclipseLink作为JPA提供程序,因此可以执行优化,例如使用@JoinFetch@BatchFetch注释(仅适用于EclipseLink)。

查看此link或参阅EclipseLink文档了解更多信息。