1

如果在请求期间由休眠 (V3.5.1) 执行 SQL 语句,我目前会遇到严重的性能问题。所以我试图深入细节以了解 Eager-fetching 的细节。

基本上,问题似乎源于我们使用的匹配实体引用两个匹配的配置文件实体的问题。似乎hibernate只急切地获取带有连接的配置文件,而不是两者。另一个由选择加载。

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

所有关联都由 FetchMode.Join 和 @ManyToOne(@OneToOne(optional=false, fetch=FetchType.EAGER, cascade=...)

我已经设置了一个简单的示例,以测试使用 HQL 和 Criterieas 的各种方法来通过 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 find 本身不会进行急切的提取,而是通过单独的选择加载 ProfileData (以及更多数据)。当然我可以添加一些 Eager Fetching Hints,但这在复杂的数据结构中是相当麻烦的。

Criteria Query 设法在一个语句中加载一侧(potentialMatch)和它的 SearchData。另一端(searchingProfile)也被获取,但从属实体(SearchData 和其他元素)然后通过显式选择获取。

问题:是否有一种优雅的方式来确保一次快速加载数据?

4

0 回答 0