mercredi 5 juillet 2017

Hibernate - how to avoid the n+1 issue while keeping a good throughput with @ManyToOne association?

I have a class Entry which has two fields serving auditing purposes: startAuditAction and endAuditAction. One audit action can affect several entries, therefore the class Entry describes ManyToOne relationships as follows:

public class Entry{
    @Id
    @Column(nullable = false)
    protected String path;

    @Id
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(nullable = false, name = "start_action_id")
    protected AuditAction startAction;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(updatable = true, nullable = true, name = "end_action_id")
    protected AuditAction endAction;
}

I want to retrieve instances of Entry based on conditions on the path field and the audit fields. For example to retrieve entries which have not yet been deleted, the HQL would look something like that:

SELECT DISTINCT entry FROM ENTRY_TABLE entry JOIN FETCH entry.startAction startAct LEFT JOIN FETCH entry.endAction endAct WHERE entry.path LIKE myPath and endAct IS NULL

I am using lazy loading together with JOIN FETCH to avoid the N+1 problem while still being able to access the audit fields. However, I have two problems with this:

  • Firstly, this really does not seem clean to me: if I know I want to access the audit fields (namely the audit actions timestamp), then they should not be lazy loaded. But if I use eager loading I am facing the n+1 problem even if I use JOIN FETCH (and in that case I do not understand why fetch = FetchType.EAGER would ever be useful)...
  • Secondly, even though I am avoiding the n+1 problem and therefore firing less SQL queries, I get some performance issues for the overall use of my database, probably because of the joins.

What is the proper way to avoid firing additional queries while preserving a good throughput ?

Thanks!

Aucun commentaire:

Enregistrer un commentaire