4

サブセレクトとイーガーがどのように機能するかを誤解していると思います。私の目標は、N+1 問題に遭遇したときのパフォーマンスを改善することです

編集休止状態がパフォーマンスと同等であることを望んでいましたが、 create SQL query メソッドを使用して自分でオブジェクトを作成する方が速いかどうか疑問に思っています。以下の例では、必要なすべてのデータを 1 つのクエリで取得できるのに、なぜ 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 つのサブクエリを実行すると予想されます。

  1. SELECT * FROM Employee INNER JOIN EmployeeArea ON条件 INNER JOIN Area ON条件
  2. SELECT * FROM Employee WHERE employeeId IN (サブクエリ 1)
  3. SELECT * FROM Area WHERE areaId IN (サブクエリ 2)

実際、前述のテスト データの 6 つの入力に対して、従業員に対して 6 つの選択、エリアに対して 6 つの選択を取得しているように見えます。そして、明らかに間違っているように見える 2 つの大きなクエリ: -

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
                )
            )

次に、面積について非常によく似たものです。

私の目標は、返されたリスト内の各従業員オブジェクトを使用して、働いていた分野を特定できるようにすることです。各エンティティにはより多くのフィールドがありますが、このテスト ケースは単純化されています。

4

2 に答える 2

3

熱心にロードしながら、JOIN戦略を使用して怠惰にリンクAreaします。ロードすると、休止状態のセッションにオブジェクトが入力されます。その後、ナビゲートしても、データベースからは何も取得されません。これは、セッション キャッシュに既にあるためです。EmployeeAreaEmployeeEmployeeAreasEmployeeEmployeeAreaEmployeeAreaEmployee.EmployeeArea.Area.EmloyeeAreaEmployeeArea

于 2013-06-13T19:26:23.933 に答える