1

現在、リクエスト中に SQL ステートメントが休止状態 (V3.5.1) によって実行されると、パフォーマンスに重大な問題が発生します。そこで、eager-fetching の詳細を理解するために詳細に飛び込もうとしました。

基本的に、この問題は、一致する 2 つのプロファイル エンティティを参照する一致するエンティティを使用しているという問題から生じているようです。休止状態は、結合を使用してプロファイルを熱心にフェッチするだけで、両方ではないようです。もう 1 つは選択によってロードされます。

[MatchingData] ---- searchingProfile--> [ProfileData] ---- searchData --> [SearchData]
                 |
                 +- potentialMatch ---> [ProfileData] ---- searchData --> [SearchData]

すべての関連付けは、FetchMode.Join および @ManyToOne(@OneToOne(optional=false, fetch=FetchType.EAGER, cascade=...) によってマークされます。

HQL と Criterias を使用して Hibernate 経由で MatchingData をフェッチするさまざまな方法をテストするために、簡単な例を設定しました。残念ながら、定型コードは大きすぎて詳細に投稿できません。オンデマンドで提供できます。

テストは

    System.out.println("-------------------- this should be a single SQL statement ? ------------------------");
    List<MatchingData> result1 = hibernateTemplate.find(
            "from MatchingData");
    openSession.clear();

    System.out.println("-------------------- this should be a single SQL statement ? ------------------------");
    List<MatchingData> result2 = hibernateTemplate.find(
    "from MatchingData where potentialMatch.firstName!=null");
    openSession.clear();

    System.out.println("-------------------- this should be a single SQL statement ? ------------------------");
    Criteria matchingDataCriteria1 = openSession.createCriteria(MatchingData.class);
    matchingDataCriteria1.createCriteria("potentialMatch").add(Restrictions.eq("firstName", FIRSTNAME_TEST_PM));
    matchingDataCriteria1.list();
    openSession.clear();

    System.out.println("-------------------- this is a a single SQL statement ? ------------------------");
    Criteria matchingDataCriteria2 = openSession.createCriteria(MatchingData.class);
    matchingDataCriteria2.list();
    openSession.clear();

データベースに 2 つの MatchingData と 3 つの関連する ProfileData がある場合、結果は次のようになります。

-------------------- this should be a single SQL statement ? ------------------------
Hibernate: select matchingda0_.id as id3_, matchingda0_.potentialMatch as potentia2_3_, matchingda0_.searchingProfile as searchin3_3_ from MatchingData matchingda0_
Hibernate: select profiledat0_.id as id0_3_, profiledat0_.firstName as firstName0_3_, profiledat0_.kontaktSparkasse_BLZ as kontaktS5_0_3_, profiledat0_.lastName as lastName0_3_, profiledat0_.profileType as profileT4_0_3_, profiledat0_.searchData_id as searchData6_0_3_, institutsd1_.BLZ as BLZ2_0_, institutsd1_.name as name2_0_, institutsd1_.parentHub_BLZ as parentHub3_2_0_, institutsd2_.BLZ as BLZ2_1_, institutsd2_.name as name2_1_, institutsd2_.parentHub_BLZ as parentHub3_2_1_, searchdata3_.id as id1_2_, searchdata3_.fakeContent as fakeCont2_1_2_ from ProfileData profiledat0_ inner join InstitutsData institutsd1_ on profiledat0_.kontaktSparkasse_BLZ=institutsd1_.BLZ left outer join InstitutsData institutsd2_ on institutsd1_.parentHub_BLZ=institutsd2_.BLZ left outer join SearchData searchdata3_ on profiledat0_.searchData_id=searchdata3_.id where profiledat0_.id=?
Hibernate: select profiledat0_.id as id0_3_, profiledat0_.firstName as firstName0_3_, profiledat0_.kontaktSparkasse_BLZ as kontaktS5_0_3_, profiledat0_.lastName as lastName0_3_, profiledat0_.profileType as profileT4_0_3_, profiledat0_.searchData_id as searchData6_0_3_, institutsd1_.BLZ as BLZ2_0_, institutsd1_.name as name2_0_, institutsd1_.parentHub_BLZ as parentHub3_2_0_, institutsd2_.BLZ as BLZ2_1_, institutsd2_.name as name2_1_, institutsd2_.parentHub_BLZ as parentHub3_2_1_, searchdata3_.id as id1_2_, searchdata3_.fakeContent as fakeCont2_1_2_ from ProfileData profiledat0_ inner join InstitutsData institutsd1_ on profiledat0_.kontaktSparkasse_BLZ=institutsd1_.BLZ left outer join InstitutsData institutsd2_ on institutsd1_.parentHub_BLZ=institutsd2_.BLZ left outer join SearchData searchdata3_ on profiledat0_.searchData_id=searchdata3_.id where profiledat0_.id=?
Hibernate: select profiledat0_.id as id0_3_, profiledat0_.firstName as firstName0_3_, profiledat0_.kontaktSparkasse_BLZ as kontaktS5_0_3_, profiledat0_.lastName as lastName0_3_, profiledat0_.profileType as profileT4_0_3_, profiledat0_.searchData_id as searchData6_0_3_, institutsd1_.BLZ as BLZ2_0_, institutsd1_.name as name2_0_, institutsd1_.parentHub_BLZ as parentHub3_2_0_, institutsd2_.BLZ as BLZ2_1_, institutsd2_.name as name2_1_, institutsd2_.parentHub_BLZ as parentHub3_2_1_, searchdata3_.id as id1_2_, searchdata3_.fakeContent as fakeCont2_1_2_ from ProfileData profiledat0_ inner join InstitutsData institutsd1_ on profiledat0_.kontaktSparkasse_BLZ=institutsd1_.BLZ left outer join InstitutsData institutsd2_ on institutsd1_.parentHub_BLZ=institutsd2_.BLZ left outer join SearchData searchdata3_ on profiledat0_.searchData_id=searchdata3_.id where profiledat0_.id=?
-------------------- this should be a single SQL statement ? ------------------------
Hibernate: select matchingda0_.id as id3_, matchingda0_.potentialMatch as potentia2_3_, matchingda0_.searchingProfile as searchin3_3_ from MatchingData matchingda0_ cross join ProfileData profiledat1_ where matchingda0_.potentialMatch=profiledat1_.id and (profiledat1_.firstName is not null)
Hibernate: select profiledat0_.id as id0_3_, profiledat0_.firstName as firstName0_3_, profiledat0_.kontaktSparkasse_BLZ as kontaktS5_0_3_, profiledat0_.lastName as lastName0_3_, profiledat0_.profileType as profileT4_0_3_, profiledat0_.searchData_id as searchData6_0_3_, institutsd1_.BLZ as BLZ2_0_, institutsd1_.name as name2_0_, institutsd1_.parentHub_BLZ as parentHub3_2_0_, institutsd2_.BLZ as BLZ2_1_, institutsd2_.name as name2_1_, institutsd2_.parentHub_BLZ as parentHub3_2_1_, searchdata3_.id as id1_2_, searchdata3_.fakeContent as fakeCont2_1_2_ from ProfileData profiledat0_ inner join InstitutsData institutsd1_ on profiledat0_.kontaktSparkasse_BLZ=institutsd1_.BLZ left outer join InstitutsData institutsd2_ on institutsd1_.parentHub_BLZ=institutsd2_.BLZ left outer join SearchData searchdata3_ on profiledat0_.searchData_id=searchdata3_.id where profiledat0_.id=?
Hibernate: select profiledat0_.id as id0_3_, profiledat0_.firstName as firstName0_3_, profiledat0_.kontaktSparkasse_BLZ as kontaktS5_0_3_, profiledat0_.lastName as lastName0_3_, profiledat0_.profileType as profileT4_0_3_, profiledat0_.searchData_id as searchData6_0_3_, institutsd1_.BLZ as BLZ2_0_, institutsd1_.name as name2_0_, institutsd1_.parentHub_BLZ as parentHub3_2_0_, institutsd2_.BLZ as BLZ2_1_, institutsd2_.name as name2_1_, institutsd2_.parentHub_BLZ as parentHub3_2_1_, searchdata3_.id as id1_2_, searchdata3_.fakeContent as fakeCont2_1_2_ from ProfileData profiledat0_ inner join InstitutsData institutsd1_ on profiledat0_.kontaktSparkasse_BLZ=institutsd1_.BLZ left outer join InstitutsData institutsd2_ on institutsd1_.parentHub_BLZ=institutsd2_.BLZ left outer join SearchData searchdata3_ on profiledat0_.searchData_id=searchdata3_.id where profiledat0_.id=?
Hibernate: select profiledat0_.id as id0_3_, profiledat0_.firstName as firstName0_3_, profiledat0_.kontaktSparkasse_BLZ as kontaktS5_0_3_, profiledat0_.lastName as lastName0_3_, profiledat0_.profileType as profileT4_0_3_, profiledat0_.searchData_id as searchData6_0_3_, institutsd1_.BLZ as BLZ2_0_, institutsd1_.name as name2_0_, institutsd1_.parentHub_BLZ as parentHub3_2_0_, institutsd2_.BLZ as BLZ2_1_, institutsd2_.name as name2_1_, institutsd2_.parentHub_BLZ as parentHub3_2_1_, searchdata3_.id as id1_2_, searchdata3_.fakeContent as fakeCont2_1_2_ from ProfileData profiledat0_ inner join InstitutsData institutsd1_ on profiledat0_.kontaktSparkasse_BLZ=institutsd1_.BLZ left outer join InstitutsData institutsd2_ on institutsd1_.parentHub_BLZ=institutsd2_.BLZ left outer join SearchData searchdata3_ on profiledat0_.searchData_id=searchdata3_.id where profiledat0_.id=?
-------------------- this should be a single SQL statement ? ------------------------
Hibernate: select this_.id as id3_5_, this_.potentialMatch as potentia2_3_5_, this_.searchingProfile as searchin3_3_5_, profiledat1_.id as id0_0_, profiledat1_.firstName as firstName0_0_, profiledat1_.kontaktSparkasse_BLZ as kontaktS5_0_0_, profiledat1_.lastName as lastName0_0_, profiledat1_.profileType as profileT4_0_0_, profiledat1_.searchData_id as searchData6_0_0_, institutsd4_.BLZ as BLZ2_1_, institutsd4_.name as name2_1_, institutsd4_.parentHub_BLZ as parentHub3_2_1_, institutsd5_.BLZ as BLZ2_2_, institutsd5_.name as name2_2_, institutsd5_.parentHub_BLZ as parentHub3_2_2_, searchdata6_.id as id1_3_, searchdata6_.fakeContent as fakeCont2_1_3_, profiledat7_.id as id0_4_, profiledat7_.firstName as firstName0_4_, profiledat7_.kontaktSparkasse_BLZ as kontaktS5_0_4_, profiledat7_.lastName as lastName0_4_, profiledat7_.profileType as profileT4_0_4_, profiledat7_.searchData_id as searchData6_0_4_ from MatchingData this_ inner join ProfileData profiledat1_ on this_.potentialMatch=profiledat1_.id left outer join InstitutsData institutsd4_ on profiledat1_.kontaktSparkasse_BLZ=institutsd4_.BLZ left outer join InstitutsData institutsd5_ on institutsd4_.parentHub_BLZ=institutsd5_.BLZ left outer join SearchData searchdata6_ on profiledat1_.searchData_id=searchdata6_.id inner join ProfileData profiledat7_ on this_.searchingProfile=profiledat7_.id where profiledat1_.firstName=?
Hibernate: select institutsd0_.BLZ as BLZ2_1_, institutsd0_.name as name2_1_, institutsd0_.parentHub_BLZ as parentHub3_2_1_, institutsd1_.BLZ as BLZ2_0_, institutsd1_.name as name2_0_, institutsd1_.parentHub_BLZ as parentHub3_2_0_ from InstitutsData institutsd0_ left outer join InstitutsData institutsd1_ on institutsd0_.parentHub_BLZ=institutsd1_.BLZ where institutsd0_.BLZ=?
Hibernate: select searchdata0_.id as id1_0_, searchdata0_.fakeContent as fakeCont2_1_0_ from SearchData searchdata0_ where searchdata0_.id=?
Hibernate: select searchdata0_.id as id1_0_, searchdata0_.fakeContent as fakeCont2_1_0_ from SearchData searchdata0_ where searchdata0_.id=?
-------------------- this should be a a single SQL statement ? ------------------------
Hibernate: select this_.id as id3_5_, this_.potentialMatch as potentia2_3_5_, this_.searchingProfile as searchin3_3_5_, profiledat2_.id as id0_0_, profiledat2_.firstName as firstName0_0_, profiledat2_.kontaktSparkasse_BLZ as kontaktS5_0_0_, profiledat2_.lastName as lastName0_0_, profiledat2_.profileType as profileT4_0_0_, profiledat2_.searchData_id as searchData6_0_0_, institutsd3_.BLZ as BLZ2_1_, institutsd3_.name as name2_1_, institutsd3_.parentHub_BLZ as parentHub3_2_1_, institutsd4_.BLZ as BLZ2_2_, institutsd4_.name as name2_2_, institutsd4_.parentHub_BLZ as parentHub3_2_2_, searchdata5_.id as id1_3_, searchdata5_.fakeContent as fakeCont2_1_3_, profiledat6_.id as id0_4_, profiledat6_.firstName as firstName0_4_, profiledat6_.kontaktSparkasse_BLZ as kontaktS5_0_4_, profiledat6_.lastName as lastName0_4_, profiledat6_.profileType as profileT4_0_4_, profiledat6_.searchData_id as searchData6_0_4_ from MatchingData this_ inner join ProfileData profiledat2_ on this_.potentialMatch=profiledat2_.id left outer join InstitutsData institutsd3_ on profiledat2_.kontaktSparkasse_BLZ=institutsd3_.BLZ left outer join InstitutsData institutsd4_ on institutsd3_.parentHub_BLZ=institutsd4_.BLZ left outer join SearchData searchdata5_ on profiledat2_.searchData_id=searchdata5_.id inner join ProfileData profiledat6_ on this_.searchingProfile=profiledat6_.id
Hibernate: select institutsd0_.BLZ as BLZ2_1_, institutsd0_.name as name2_1_, institutsd0_.parentHub_BLZ as parentHub3_2_1_, institutsd1_.BLZ as BLZ2_0_, institutsd1_.name as name2_0_, institutsd1_.parentHub_BLZ as parentHub3_2_0_ from InstitutsData institutsd0_ left outer join InstitutsData institutsd1_ on institutsd0_.parentHub_BLZ=institutsd1_.BLZ where institutsd0_.BLZ=?
Hibernate: select searchdata0_.id as id1_0_, searchdata0_.fakeContent as fakeCont2_1_0_ from SearchData searchdata0_ where searchdata0_.id=?
Hibernate: select searchdata0_.id as id1_0_, searchdata0_.fakeContent as fakeCont2_1_0_ from SearchData searchdata0_ where searchdata0_.id=?

私が理解しているように: HQL の検索は、それ自体で熱心なフェッチを行うのではなく、個々の選択によって ProfileData (およびその他のデータ) をロードします。もちろん、Eager Fetching Hint を追加することもできますが、これは複雑なデータ構造では非常に面倒です。

Criteria Query は、その SearchData と一緒に 1 つのステートメントで熱心な読み込みを使用して片側 (potentialMatch) を読み込むことができます。反対側 (searchingProfile) も取得されますが、従属エンティティ (SearchData およびその他の要素) は明示的な選択によって取得されます。

質問: 1 つの迅速なデータの読み込みを確実にするエレガントな方法はありますか?

4

0 に答える 0