Skip to content

Commit f8275f1

Browse files
committed
HHH-16624 Do not create subselects when there are fewer than 2 results
1 parent 4c1d8a1 commit f8275f1

File tree

9 files changed

+41
-28
lines changed

9 files changed

+41
-28
lines changed

hibernate-core/src/main/java/org/hibernate/engine/spi/SubselectFetch.java

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,12 @@
1313
import java.util.Set;
1414

1515
import org.hibernate.spi.NavigablePath;
16-
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
1716
import org.hibernate.sql.ast.tree.from.TableGroup;
1817
import org.hibernate.sql.ast.tree.select.QuerySpec;
1918
import org.hibernate.sql.ast.tree.select.SelectStatement;
2019
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
2120
import org.hibernate.sql.exec.spi.JdbcParametersList;
22-
import org.hibernate.sql.results.graph.DomainResult;
2321
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
24-
import org.hibernate.sql.results.graph.entity.internal.EntityResultInitializer;
2522

2623
/**
2724
* Encapsulates details related to entities which contain sub-select-fetchable
@@ -151,8 +148,7 @@ private StandardRegistrationHandler(
151148

152149
public void addKey(EntityKey key, LoadingEntityEntry entry) {
153150
if ( batchFetchQueue.getSession().getLoadQueryInfluencers()
154-
.hasSubselectLoadableCollections( entry.getDescriptor() )
155-
&& shouldAddSubselectFetch( entry ) ) {
151+
.hasSubselectLoadableCollections( entry.getDescriptor() ) ) {
156152
final SubselectFetch subselectFetch = subselectFetches.computeIfAbsent(
157153
entry.getEntityInitializer().getNavigablePath(),
158154
navigablePath -> new SubselectFetch(
@@ -169,23 +165,5 @@ && shouldAddSubselectFetch( entry ) ) {
169165
batchFetchQueue.addSubselect( key, subselectFetch );
170166
}
171167
}
172-
173-
private boolean shouldAddSubselectFetch(LoadingEntityEntry entry) {
174-
if ( entry.getEntityInitializer() instanceof EntityResultInitializer ) {
175-
return true;
176-
}
177-
else {
178-
final NavigablePath entityInitializerParent = entry.getEntityInitializer().getNavigablePath().getParent();
179-
180-
// We want to add only the collections of the loading entities
181-
for ( DomainResult<?> domainResult : loadingSqlAst.getDomainResultDescriptors() ) {
182-
if ( domainResult.getNavigablePath().equals( entityInitializerParent ) ) {
183-
return true;
184-
}
185-
}
186-
187-
return false;
188-
}
189-
}
190168
}
191169
}

hibernate-core/src/main/java/org/hibernate/sql/exec/spi/ExecutionContext.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,22 @@ default EntityMappingType getRootEntityDescriptor() {
6060
return null;
6161
}
6262

63+
/**
64+
*
65+
* @param entityKey
66+
* @param entry
67+
*
68+
* @deprecated use {@link #registerSubselect(EntityKey, LoadingEntityEntry)} instead.
69+
*/
70+
@Deprecated
6371
default void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
6472
// by default do nothing
6573
}
6674

75+
default void registerSubselect(EntityKey entityKey, LoadingEntityEntry entry) {
76+
registerLoadingEntityEntry( entityKey, entry );
77+
}
78+
6779
/**
6880
* Hook to allow delaying calls to {@link LogicalConnectionImplementor#afterStatement()}.
6981
* Mainly used in the case of batching and multi-table mutations

hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NestedRowProcessingState.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import org.hibernate.engine.spi.CollectionKey;
1010
import org.hibernate.engine.spi.EntityKey;
11+
import org.hibernate.engine.spi.SubselectFetch;
1112
import org.hibernate.metamodel.mapping.EntityMappingType;
1213
import org.hibernate.query.spi.QueryOptions;
1314
import org.hibernate.query.spi.QueryParameterBindings;

hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardRowReader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ public InitializersList getInitializersList() {
8383
@Override
8484
public T readRow(RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) {
8585
LoadingLogger.LOGGER.trace( "StandardRowReader#readRow" );
86-
8786
coordinateInitializers( rowProcessingState );
8887

8988
final Object[] resultRow = new Object[ assemblerCount ];
@@ -112,6 +111,7 @@ private void coordinateInitializers(RowProcessingState rowProcessingState) {
112111

113112
@Override
114113
public void finishUp(JdbcValuesSourceProcessingState processingState) {
114+
processingState.registerSubselect();
115115
initializers.endLoading( processingState.getExecutionContext() );
116116
}
117117

hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesSourceProcessingStateStandardImpl.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import org.hibernate.event.spi.PostLoadEvent;
2121
import org.hibernate.event.spi.PostLoadEventListener;
2222
import org.hibernate.event.spi.PreLoadEvent;
23+
import org.hibernate.internal.CoreLogging;
24+
import org.hibernate.internal.CoreMessageLogger;
2325
import org.hibernate.query.spi.QueryOptions;
2426
import org.hibernate.sql.exec.spi.Callback;
2527
import org.hibernate.sql.exec.spi.ExecutionContext;
@@ -36,6 +38,8 @@
3638
*/
3739
public class JdbcValuesSourceProcessingStateStandardImpl implements JdbcValuesSourceProcessingState {
3840

41+
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( JdbcValuesSourceProcessingStateStandardImpl.class );
42+
3943
private final ExecutionContext executionContext;
4044
private final JdbcValuesSourceProcessingOptions processingOptions;
4145

@@ -97,7 +101,6 @@ public void registerLoadingEntity(
97101
if ( loadingEntityMap == null ) {
98102
loadingEntityMap = new HashMap<>();
99103
}
100-
executionContext.registerLoadingEntityEntry( entityKey, loadingEntry );
101104
loadingEntityMap.put( entityKey, loadingEntry );
102105
}
103106

@@ -137,6 +140,22 @@ public LoadingCollectionEntry findLoadingCollectionLocally(CollectionKey key) {
137140
return loadingCollectionMap.get( key );
138141
}
139142

143+
@Override
144+
public void registerSubselect() {
145+
if ( loadingEntityMap != null && loadingEntityMap.size() > 1 ) {
146+
loadingEntityMap.forEach(
147+
(entityKey, loadingEntityEntry) ->
148+
executionContext.registerSubselect( entityKey, loadingEntityEntry )
149+
);
150+
}
151+
else {
152+
LOG.tracef(
153+
"Skipping create subselects because there are fewer than 2 results, so query by key is more efficient.",
154+
getClass().getName()
155+
);
156+
}
157+
}
158+
140159
@Override
141160
public void registerLoadingCollection(CollectionKey key, LoadingCollectionEntry loadingCollectionEntry) {
142161
if ( loadingCollectionMap == null ) {

hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/spi/JdbcValuesSourceProcessingState.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,8 @@ void registerLoadingCollection(
8080
CollectionKey collectionKey,
8181
LoadingCollectionEntry loadingCollectionEntry);
8282

83+
default void registerSubselect() {
84+
}
85+
8386
void finishUp();
8487
}

hibernate-core/src/test/java/org/hibernate/orm/test/mapping/fetch/depth/DepthOneBatchTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public void tesGetAgency(SessionFactoryScope scope) {
104104
);
105105

106106
assertThat( executedQueries.get( 4 ).toLowerCase() ).isEqualTo(
107-
"select u1_0.group_id,u1_1.user_id,a1_0.agency_id,a1_0.agency_txt,u1_1.user_name from group_user u1_0 join user_table u1_1 on u1_1.user_id=u1_0.user_id left join agency_table a1_0 on a1_0.agency_id=u1_1.agency_id where u1_0.group_id in (select g1_0.group_id from group_table g1_0 where g1_0.agency_id=?)"
107+
"select u1_0.group_id,u1_1.user_id,a1_0.agency_id,a1_0.agency_txt,u1_1.user_name from group_user u1_0 join user_table u1_1 on u1_1.user_id=u1_0.user_id left join agency_table a1_0 on a1_0.agency_id=u1_1.agency_id where u1_0.group_id=?"
108108
);
109109

110110
}

hibernate-core/src/test/java/org/hibernate/orm/test/mapping/fetch/depth/DepthOneTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public void tesGetAgency(SessionFactoryScope scope) {
100100
);
101101

102102
assertThat( executedQueries.get( 3 ).toLowerCase() ).isEqualTo(
103-
"select u1_0.group_id,u1_1.user_id,a1_0.agency_id,a1_0.agency_txt,u1_1.user_name from group_user u1_0 join user_table u1_1 on u1_1.user_id=u1_0.user_id left join agency_table a1_0 on a1_0.agency_id=u1_1.agency_id where u1_0.group_id in (select g1_0.group_id from group_table g1_0 where g1_0.agency_id=?)"
103+
"select u1_0.group_id,u1_1.user_id,a1_0.agency_id,a1_0.agency_txt,u1_1.user_name from group_user u1_0 join user_table u1_1 on u1_1.user_id=u1_0.user_id left join agency_table a1_0 on a1_0.agency_id=u1_1.agency_id where u1_0.group_id=?"
104104
);
105105

106106
assertThat( executedQueries.get( 4 ).toLowerCase() ).isEqualTo(

hibernate-core/src/test/java/org/hibernate/orm/test/mapping/fetch/subselect/SubselectOneToManyTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public void testShouldJoin(SessionFactoryScope scope) {
109109
assertThat( parent.getChildren() ).hasSize( 2 );
110110
statementInspector.assertExecutedCount( 3 ); // 1 query for parent, 1 for grandparent, 1 for children
111111
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 1 );
112-
statementInspector.assertNumberOfOccurrenceInQuery( 2, "join", 1 );
112+
statementInspector.assertNumberOfOccurrenceInQuery( 2, "join", 0 );
113113
} );
114114
}
115115

0 commit comments

Comments
 (0)