Skip to content

Commit 7cc3e57

Browse files
authored
fix: improve data loader query memory usage (#252)
* fix: improve data loader query memory usage * fix: optimize batch loader memory usage
1 parent bb44a34 commit 7cc3e57

File tree

2 files changed

+30
-34
lines changed

2 files changed

+30
-34
lines changed

graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaQueryFactory.java

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -335,32 +335,23 @@ protected TypedQuery<Object> getKeysQuery(DataFetchingEnvironment environment, F
335335
}
336336

337337
protected Map<Object, List<Object>> loadOneToMany(DataFetchingEnvironment environment,
338-
Set<Object> keys) {
338+
Set<Object> keys) {
339339
Field field = environment.getField();
340340

341341
TypedQuery<Object[]> query = getBatchQuery(environment, field, isDefaultDistinct(), keys);
342342

343-
if (logger.isDebugEnabled()) {
344-
logger.info("\nGraphQL JPQL Batch Query String:\n {}", getJPQLQueryString(query));
345-
}
346-
347-
List<Object[]> resultList = query.getResultList();
343+
List<Object[]> resultList = getResultList(query);
348344

349345
Map<Object, List<Object>> batch = resultList.stream()
346+
.peek(t -> entityManager.detach(t[1]))
350347
.collect(groupingBy(t -> t[0],
351348
Collectors.mapping(t -> t[1],
352349
GraphQLSupport.toResultList())));
353-
Map<Object, List<Object>> resultMap = new LinkedHashMap<>();
350+
Map<Object, List<Object>> resultMap = new LinkedHashMap<>(keys.size());
354351

355352
keys.forEach(it -> {
356353
List<Object> list = batch.getOrDefault(it, Collections.emptyList());
357354

358-
if (!list.isEmpty()) {
359-
list = list.stream()
360-
.filter(GraphQLSupport.distinctByKey(GraphQLSupport::identityToString))
361-
.collect(Collectors.toList());
362-
}
363-
364355
resultMap.put(it, list);
365356
});
366357

@@ -369,30 +360,33 @@ protected Map<Object, List<Object>> loadOneToMany(DataFetchingEnvironment enviro
369360

370361
protected Map<Object, Object> loadManyToOne(DataFetchingEnvironment environment,
371362
Set<Object> keys) {
372-
Field field = environment.getField();
373-
374-
TypedQuery<Object[]> query = getBatchQuery(environment, field, isDefaultDistinct(), keys);
363+
Field field = environment.getField();
375364

376-
if (logger.isDebugEnabled()) {
377-
logger.info("\nGraphQL JPQL Batch Query String:\n {}", getJPQLQueryString(query));
378-
}
365+
TypedQuery<Object[]> query = getBatchQuery(environment, field, isDefaultDistinct(), keys);
379366

380-
List<Object[]> resultList = query.getResultList();
367+
List<Object[]> resultList = getResultList(query);
381368

382-
Map<Object, Object> batch = new LinkedHashMap<>();
369+
Map<Object, Object> resultMap = new LinkedHashMap<>(resultList.size());
383370

384-
resultList.forEach(item -> batch.put(item[0], item[1]));
371+
resultList.stream()
372+
.peek(t -> entityManager.detach(t[1]))
373+
.forEach(item -> resultMap.put(item[0], item[1]));
385374

386-
Map<Object, Object> resultMap = new LinkedHashMap<>();
375+
return resultMap;
376+
}
387377

388-
keys.forEach(it -> {
389-
Object list = batch.getOrDefault(it, null);
378+
protected <T> List<T> getResultList(TypedQuery<T> query) {
379+
if (logger.isDebugEnabled()) {
380+
logger.info("\nGraphQL JPQL Batch Query String:\n {}", getJPQLQueryString(query));
381+
}
390382

391-
resultMap.put(it, list);
392-
});
383+
// Let' try reduce overhead and disable all caching
384+
query.setHint(ORG_HIBERNATE_READ_ONLY, true);
385+
query.setHint(ORG_HIBERNATE_FETCH_SIZE, defaultFetchSize);
386+
query.setHint(ORG_HIBERNATE_CACHEABLE, false);
393387

394-
return resultMap;
395-
}
388+
return query.getResultList();
389+
}
396390

397391
@SuppressWarnings( { "rawtypes", "unchecked" } )
398392
protected TypedQuery<Object[]> getBatchQuery(DataFetchingEnvironment environment, Field field, boolean isDistinct, Set<Object> keys) {
@@ -599,11 +593,8 @@ protected final List<Predicate> getFieldPredicates(Field field, CriteriaQuery<?>
599593
// Let's join fetch element collections to avoid filtering their values used where search criteria
600594
if(PersistentAttributeType.ELEMENT_COLLECTION == attribute.getPersistentAttributeType()) {
601595
from.fetch(selection.getName(), JoinType.LEFT);
602-
} else if(!whereArgument.isPresent()) {
603-
// Let's apply fetch join to retrieve associated plural attributes
604-
if (!hasAnySelectionOrderBy(selection)) {
605-
fetch = reuseFetch(from, selection.getName(), isOptional);
606-
}
596+
} else if(!whereArgument.isPresent() && !hasAnySelectionOrderBy(selection)) {
597+
fetch = reuseFetch(from, selection.getName(), isOptional);
607598
}
608599
}
609600
// Let's build join fetch graph to avoid Hibernate error:

graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/support/GraphQLSupport.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,11 @@ public static Collector<Object, List<Object>, List<Object>> toResultList() {
159159
left.addAll(right);
160160
return left;
161161
},
162+
(list) -> {
163+
return list.stream()
164+
.filter(GraphQLSupport.distinctByKey(GraphQLSupport::identityToString))
165+
.collect(Collectors.toList());
166+
},
162167
Collector.Characteristics.CONCURRENT);
163168
}
164169

0 commit comments

Comments
 (0)