简体   繁体   中英

Hibernate Select Queries Optimization

I'm searching for the best way to optimize Hibernate select queries.

Here is a basic example:

BDD model 1 Client -> n Contracts -> n Options

The simplest manner to request all data of the client "xxxx" is something like:

final Query hqlQuery = jdbcTemplate.createHQLQuery("from Client cli left join fetch cli.contracts con left join fetch con.options where cli.id=:idClient");
hqlQuery .setString("idClient", "xxxx");

Client client = (Client) hqlQuery.uniqueResult();

Sometimes this is just not possible since there are two much data to return.

So, I split the request, somethink like:

// Query 1
final Query hqlQueryClient = jdbcTemplate.createHQLQuery("from Client cli left join fetch cli.contracts where cli.id=:clientId");
hqlQueryClient.setString("clientId", "xxxx");

Client client = (Client) hqlQueryClient.uniqueResult();

List<String> listContractIds = new ArrayList<String>();

for (Contract contract : client.getContracts()) {
  listContractIds.add(contract.getId());
}

// Query 2
final Query hqlQueryOptions = jdbcTemplate.createHQLQuery("from Option opt where opt.contract.id in(:contractIds)");
hqlQueryOptions.setParameterList("contractIds", listContractIds);

List<Option> options = hqlQueryClient.list();

But, with the second manner, I can't "inject" options in client object, so I have to deal with client and options objects in my code, and search in options list those which correspond to the contract I'm working with.

Is there a way to complete Hibernate object (client in my example) with values requested in a second time ?

Thanks for your help.

PS: ask if it's not clear, I'm French guy :)

<rant> I generally hate hibernate because it's such a time waster and also seems to run hundreds of queries when you'd only run a handful if writing the SQL manually <\\rant>

If forced to use hibernate, I'd probably use 3 queries similar to

  • from Options as o join fetch o.contract as co join fetch co.client as cl where cl = :client
  • from Contracts as co join fetch co.client as cl where cl = :client
  • from Client where clientId = :clientId

Then I'd put them all into appropriate Map<Long, List> maps and do the joins in java.

First: how much data do You have in result that the first query doesn't work? If you the result has so many rows and You want to optimise this query check if all data You get from db You realy need. Maybe You should make a projection to other object which is more flattened.

If you not process the data in Java and only passing it to the front-end consider pageing the result.

The benefit in using Hibernate is ORM. You could set up your classes as Entities. So you don't need to worry about simple queries anymore. Simply use JPA for that task. The entities could look like that:

@Entity
public class Client implements Serializable {
    private Long id;
    private ArrayList<Contract> contracts;
    // more attributes here
    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getId() {
        return id;
    }

    @OneToMany
    public ArrayList<Contract> getContracts() {
        return contracts;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setContracts(ArrayList<Contract> contracts) {
        this.contracts = contracts;
    }
}

@Entity
public class Contract implements Serializable {
    private Long id;
    private List<Option> options;
    // more attributes here
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getId() {
        return id;
    }

    @OneToMany
    public List<Option> getOptions() {
        return options;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setOptions(List<Option> options) {
        this.options = options;
    }
}

and so on...

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