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

Improve JPA performance Bidirectional mapping " n+1 select "

我有两个实体 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();

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

SELECT t1.ID, t1.activity, t1.last_name, t1.matricule, t0.NAME, t0.parent_id 来自 person t1 LEFT OUTER加入 GROUP_OF_PERSONS t0 ON (t0.ID = t1.group_id)

Thread(Thread[main,5,main])--SELECT ID, employ_date, first_name, 性别, last_name, 矩阵, phone_number, 标题, group_id 来自哪里的人 (group_id = ?) 绑定 => [5302]

Thread(Thread[main,5,main])--SELECT ID, employ_date, first_name, 性别, last_name, 矩阵, phone_number, 标题, group_id 来自哪里的人 (group_id = ?) 绑定 => [6965]

Thread(Thread[main,5,main])--SELECT ID, employ_date, first_name, 性别, last_name, 矩阵, phone_number, 标题, group_id 来自哪里的人 (group_id = ?) 绑定 => [6980]

Thread(Thread[main,5,main])--SELECT ID, employ_date, first_name, 性别, last_name, 矩阵, phone_number, 标题, group_id 来自哪里的人 (group_id = ?)

您正在查询中使用 fetch(以包含父 Person 实体的 'group' 子元素)。这是预期的行为,因此您将遇到常见的 N+1 SQL SELECT 问题。但是,由于您使用 EclipseLink 作为 JPA 提供程序,您可以进行优化,例如使用 @JoinFetch@BatchFetch 注释(仅特定于 EclipseLink)。

查看此 link 或查看 EclipseLink 文档以获取更多信息。

问题出在您的 Person->Group 关系上。它被标记为急切且没有任何获取选项,强制对从初始查询中读入的每个人进行单独查询。将查询标记为使用如上所述的连接或批量提取,或者使用您在 Group->Person 关系上使用的相同或相似的 OUTER 选项,以便在单个查询中全部提取。

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