Description
I detected a strange performance issue that I'd like to share.
My goal is to find all rows based on a querydsl
Predicate
, and return them as a stream of Projections
.
Now I created this function once in a Repository
interface, and once manually using JPAQuery
.
Surprisingly. the JPAQuery
only takes 50% of the time, even though the resulting query should be equal.
public interface MyEntityRepository extends JpaRepository<MyEntity, Long>, QuerydslPredicateExecutor<MyEntity> {
}
Usage:
try (Stream<MyEntityView> stream = dao.findBy(predicate, q -> q.as(MyEntityView.class).stream())) {
stream.forEach(row -> {});
}
Whereas MyEntityView
is a projection interface with only some fields of the real entity.
Now the "manual" query, whereas MyEntityView
is a real class with a constructor in this case:
try(Stream<FlightCacheGdsView2> stream = new JPAQuery<>(em)
.select(Projections.constructor(MyEntityView.class,
QMyEntity.myEntity.field1, QMyEntity.myEntity.field2, QMyEntity.myEntity.field5))
.from(QMyEntity.myEntity)
.where(predicate)
.stream()) {
stream.forEach(row -> {});
}
So maybe anybody has an explaination for this performance gain then using JPAQuery
manually? I don't think this happens just by chance. Maybe it's a bug?
At the end, both approaches are calling AbstractJPAQuery.stream()
, so I wonder why there is a difference at all.
Update: what I just found the reason: the findBy()
method creates a query that selects all fields from the database. select myEntity from MyEntity myEntity where...
.
Whereas the JPAQuery
only selects the desired fields for the projection (select field1, field2, field5 from myEntity...
).
So probably this is a bug in cases where a Projection
interface is passed to the FetchableFluentQuery
function?