我相信我误解了 subselect 和 eager 的工作原理;我的目标是在遇到 N+1 问题时提高性能
编辑我想知道只使用 create SQL 查询方法并自己创建对象是否会更快,尽管我希望 hibernate 能与性能相提并论。在下面的示例中,我可以在单个查询中提取所有所需的数据,那么为什么 hibernate 对每个数据都进行单独的查询呢?
我创建了以下测试用例来突出我的问题,请原谅这个模型的粗鲁。
@Entity
@Table(name = "Area")
public class Area implements Serializable
{
@Id
@GeneratedValue(generator = "areaId" )
@GenericGenerator(name = "areaId", strategy = "uuid2")
public String areaId;
@OneToMany(mappedBy = "area", fetch=FetchType.EAGER)
@Fetch(FetchMode.SUBSELECT)
public Set<EmployeeArea> employeeAreas = new HashSet<EmployeeArea>();
}
@Entity
@Table(name = "Employee")
public class Employee implements Serializable
{
@Id
@GeneratedValue(generator = "employeeId" )
@GenericGenerator(name = "employeeId", strategy = "uuid2")
public String employeeId;
@OneToMany(mappedBy = "employee", fetch=FetchType.EAGER)
@Fetch(FetchMode.SUBSELECT)
public Set<EmployeeArea> employeeAreas = new HashSet<EmployeeArea>();
}
@Entity
@Table(name = "EmployeeArea")
public class EmployeeArea implements Serializable
{
@Id
@GeneratedValue(generator = "employeeAreaId" )
@GenericGenerator(name = "employeeAreaId", strategy = "uuid2")
public String employeeAreaId;
@Id
@ManyToOne
public Employee employee;
@Id
@ManyToOne
public Area area;
}
然后我填充了一些示例测试数据:-
Employee employee = new Employee();
Area area = new Area();
EmployeeArea employeeArea = new EmployeeArea();
employeeArea.area = area;
employeeArea.employee = employee;
session.save(employee);
session.save(area);
session.save(employeeArea);
这可以运行几次以提供一些数据。
然后我执行以下操作: -
session.createQuery("FROM Employee e INNER JOIN e.employeeAreas ea INNER JOIN ea.area").list();
我进行 JOIN 的原因是我可以执行专家搜索。我正在查看标准,但似乎它不允许我用 WHERE 做所有我能做的事情
我希望它最多会执行 3 个查询和 2 个子查询。
- SELECT * FROM Employee INNER JOIN EmployeeArea ON 条件 INNER JOIN Area ON 条件
- SELECT * FROM Employee WHERE employeeId IN(子查询 1)
- SELECT * FROM Area WHERE areaId IN(子查询 2)
事实上,对于上述测试数据的 6 个输入,我似乎得到了 6 个员工的选择,6 个区域的选择,这看起来像是我对“1”的假设查询。然后是两个看起来完全错误的更大查询:-
select employeear0_.employee_employeeId as employee2_3_2_, employeear0_.employeeAreaId as employee1_4_2_, employeear0_.employee_employeeId as employee2_4_2_, employeear0_.area_areaId as area3_4_2_, employeear0_.employeeAreaId as employee1_4_1_, employeear0_.employee_employeeId as employee2_4_1_, employeear0_.area_areaId as area3_4_1_, area1_.areaId as areaId1_0_0_ from EmployeeArea employeear0_ inner join Area area1_ on employeear0_.area_areaId=area1_.areaId where employeear0_.employee_employeeId in ( select employee1_.employeeId from EmployeeArea employeear0_ inner join Employee employee1_ on employeear0_.employee_employeeId=employee1_.employeeId where employeear0_.area_areaId in ( select area2_.areaId from Employee employee0_ inner join EmployeeArea employeear1_ on employee0_.employeeId=employeear1_.employee_employeeId inner join Area area2_ on employeear1_.area_areaId=area2_.areaId ) )
然后是一个非常相似的区域。
我的目标是能够使用返回列表中的每个员工对象来识别工作的区域。每个实体中会有更多的字段,但是这个测试用例已经被简化了。