HHH-16624 Do not create subselects when there are fewer than 2 results
This commit is contained in:
parent
4c1d8a19bf
commit
f8275f1a70
|
@ -13,15 +13,12 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.select.QuerySpec;
|
||||
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.JdbcParametersList;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.graph.entity.internal.EntityResultInitializer;
|
||||
|
||||
/**
|
||||
* Encapsulates details related to entities which contain sub-select-fetchable
|
||||
|
@ -151,8 +148,7 @@ public class SubselectFetch {
|
|||
|
||||
public void addKey(EntityKey key, LoadingEntityEntry entry) {
|
||||
if ( batchFetchQueue.getSession().getLoadQueryInfluencers()
|
||||
.hasSubselectLoadableCollections( entry.getDescriptor() )
|
||||
&& shouldAddSubselectFetch( entry ) ) {
|
||||
.hasSubselectLoadableCollections( entry.getDescriptor() ) ) {
|
||||
final SubselectFetch subselectFetch = subselectFetches.computeIfAbsent(
|
||||
entry.getEntityInitializer().getNavigablePath(),
|
||||
navigablePath -> new SubselectFetch(
|
||||
|
@ -169,23 +165,5 @@ public class SubselectFetch {
|
|||
batchFetchQueue.addSubselect( key, subselectFetch );
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldAddSubselectFetch(LoadingEntityEntry entry) {
|
||||
if ( entry.getEntityInitializer() instanceof EntityResultInitializer ) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
final NavigablePath entityInitializerParent = entry.getEntityInitializer().getNavigablePath().getParent();
|
||||
|
||||
// We want to add only the collections of the loading entities
|
||||
for ( DomainResult<?> domainResult : loadingSqlAst.getDomainResultDescriptors() ) {
|
||||
if ( domainResult.getNavigablePath().equals( entityInitializerParent ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,10 +60,22 @@ public interface ExecutionContext {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param entityKey
|
||||
* @param entry
|
||||
*
|
||||
* @deprecated use {@link #registerSubselect(EntityKey, LoadingEntityEntry)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
default void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||
// by default do nothing
|
||||
}
|
||||
|
||||
default void registerSubselect(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||
registerLoadingEntityEntry( entityKey, entry );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to allow delaying calls to {@link LogicalConnectionImplementor#afterStatement()}.
|
||||
* Mainly used in the case of batching and multi-table mutations
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.sql.results.graph.embeddable.internal;
|
|||
|
||||
import org.hibernate.engine.spi.CollectionKey;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.SubselectFetch;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
|
|
|
@ -83,7 +83,6 @@ public class StandardRowReader<T> implements RowReader<T> {
|
|||
@Override
|
||||
public T readRow(RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) {
|
||||
LoadingLogger.LOGGER.trace( "StandardRowReader#readRow" );
|
||||
|
||||
coordinateInitializers( rowProcessingState );
|
||||
|
||||
final Object[] resultRow = new Object[ assemblerCount ];
|
||||
|
@ -112,6 +111,7 @@ public class StandardRowReader<T> implements RowReader<T> {
|
|||
|
||||
@Override
|
||||
public void finishUp(JdbcValuesSourceProcessingState processingState) {
|
||||
processingState.registerSubselect();
|
||||
initializers.endLoading( processingState.getExecutionContext() );
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ import org.hibernate.event.spi.EventSource;
|
|||
import org.hibernate.event.spi.PostLoadEvent;
|
||||
import org.hibernate.event.spi.PostLoadEventListener;
|
||||
import org.hibernate.event.spi.PreLoadEvent;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.sql.exec.spi.Callback;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
|
@ -36,6 +38,8 @@ import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
|
|||
*/
|
||||
public class JdbcValuesSourceProcessingStateStandardImpl implements JdbcValuesSourceProcessingState {
|
||||
|
||||
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( JdbcValuesSourceProcessingStateStandardImpl.class );
|
||||
|
||||
private final ExecutionContext executionContext;
|
||||
private final JdbcValuesSourceProcessingOptions processingOptions;
|
||||
|
||||
|
@ -97,7 +101,6 @@ public class JdbcValuesSourceProcessingStateStandardImpl implements JdbcValuesSo
|
|||
if ( loadingEntityMap == null ) {
|
||||
loadingEntityMap = new HashMap<>();
|
||||
}
|
||||
executionContext.registerLoadingEntityEntry( entityKey, loadingEntry );
|
||||
loadingEntityMap.put( entityKey, loadingEntry );
|
||||
}
|
||||
|
||||
|
@ -137,6 +140,22 @@ public class JdbcValuesSourceProcessingStateStandardImpl implements JdbcValuesSo
|
|||
return loadingCollectionMap.get( key );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerSubselect() {
|
||||
if ( loadingEntityMap != null && loadingEntityMap.size() > 1 ) {
|
||||
loadingEntityMap.forEach(
|
||||
(entityKey, loadingEntityEntry) ->
|
||||
executionContext.registerSubselect( entityKey, loadingEntityEntry )
|
||||
);
|
||||
}
|
||||
else {
|
||||
LOG.tracef(
|
||||
"Skipping create subselects because there are fewer than 2 results, so query by key is more efficient.",
|
||||
getClass().getName()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerLoadingCollection(CollectionKey key, LoadingCollectionEntry loadingCollectionEntry) {
|
||||
if ( loadingCollectionMap == null ) {
|
||||
|
|
|
@ -80,5 +80,8 @@ public interface JdbcValuesSourceProcessingState {
|
|||
CollectionKey collectionKey,
|
||||
LoadingCollectionEntry loadingCollectionEntry);
|
||||
|
||||
default void registerSubselect() {
|
||||
}
|
||||
|
||||
void finishUp();
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ public class DepthOneBatchTest {
|
|||
);
|
||||
|
||||
assertThat( executedQueries.get( 4 ).toLowerCase() ).isEqualTo(
|
||||
"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=?)"
|
||||
"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=?"
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ public class DepthOneTest {
|
|||
);
|
||||
|
||||
assertThat( executedQueries.get( 3 ).toLowerCase() ).isEqualTo(
|
||||
"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=?)"
|
||||
"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=?"
|
||||
);
|
||||
|
||||
assertThat( executedQueries.get( 4 ).toLowerCase() ).isEqualTo(
|
||||
|
|
|
@ -109,7 +109,7 @@ public class SubselectOneToManyTest {
|
|||
assertThat( parent.getChildren() ).hasSize( 2 );
|
||||
statementInspector.assertExecutedCount( 3 ); // 1 query for parent, 1 for grandparent, 1 for children
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 1 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 2, "join", 1 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 2, "join", 0 );
|
||||
} );
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue