提高 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 选项,以便在单个查询中全部提取。
更好的是,除非您真的需要在应用程序的每个部分中获取关系,否则请保持惰性。
我有两个实体 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 选项,以便在单个查询中全部提取。
更好的是,除非您真的需要在应用程序的每个部分中获取关系,否则请保持惰性。