简体   繁体   中英

Efficient JPQL query for retrieving complex entities

I'm quite the rookie with JPA/JPQL, so please excuse me if this question is not crystal clear.

I am trying to find an efficient JQPL query in order to get all records of a complex object.

(ie. represented by multiple tables, with several one-to-many relationships - see simplified example below):

class ComplexObject {
    private Set< SubOject1> so1 ...
    .....
    @OneToMany(fetch = FetchType.LAZY)
    public Set< SubOject1>...
}

class SubObject1 {
    private Set< SubOject2> so2 ...
    .....
    @OneToMany(fetch = FetchType.LAZY)
    public Set< SubOject2>...
}

I am using the following JPQL query :

select distinct CO 
from ComplexObject CO 
left join fetch CO.so1 SO1 
left join fetch SO1.so2

The query is run on a stateless session, in order to get a de facto snapshot of the current data in the DB, which is detached from the entity manager (hence the usage of left join fetch).

Unfortunately, I've encountered 2 problems :

  1. Since the complex object contains multiple instances of so1, and each so1 instance contains multiple instances of so2, the underlying translation to SQL queries generates a specific select query per row of the product of all the table joins - a very wasteful solution. Is there a way to reduce the number of internal select queries? (This seems like the dreaded N+1 queries problem).

  2. The JPQL query returns a ComplexObject instance per internal SQL query on the product of all the table joins - which means multiple references to the ComplexObject instances. Why does this happen on a 'select distinct' query?

The JPA framework I am using is hibernate, and the DB is HyperSQL.

The (1) issue turned out to be related to using the p6spy logging framework, which printed out all the results from a large DB table. The logging format led to an incorrect assumption that many queries where being executed.

While trying to fine tune performance, using native queries did not appear to have better performance then using JPQL queries. Using a Native Query also resulted in Object typed results, which required post processing.

You can use View Objects to receive only the columns what you want:

StringBuilder sb = new StringBuilder();
sb.append(" SELECT new ").append(ObjectVO.class.getName()).append("(co.someInfo1, co.someInfo2, so1.someInfo )");
sb.append(" FROM ComplexObject co ");
sb.append(" JOIN co.subOject1s so1 ");
sb.append(" LEFT JOIN so1.so2 so2 ");
sb.append(" WHERE so1.id = :idSo1 AND so2 = :someThing");

Query q = em.createQuery(sb.toString());
q.setParameter("idSo1", idSo1);
q.setParameter("someThing", someThing);

List<ObjectVO> listResult = q.getResultList();

The ObjectVO class:

public class ObjectVO {

    private String info1;
    private Long info2; 
    private String info3;

    public PedidoModel(String info1, Long info2, String info3){
        this.info1 = info1;
        this.info2 = info2;
        this.info3 = info3;
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM