Vermeidung von n+1 eager-fetching des Kindes collection-element association
Habe ich die folgenden Klassen:
@Entity
@Table(name = "base")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING)
@ForceDiscriminator
public class Base {
//...
}
@Entity
@DiscriminatorValue("foo")
public class Foo extends Base {
@OneToMany( mappedBy = "foo", cascade=CascadeType.ALL )
private List<Bar> bars = new ArrayList<Bar>();
//...
}
@Entity
public class Bar {
@ManyToOne (optional = false)
@JoinColumn(name = "foo_id" )
private Foo foo;
@OneToOne
@JoinColumn(name = "baz_id", nullable = false)
private Baz baz;
//...
}
@Entity
public class Baz {
//...
}
Ich jetzt im Grunde wollen laden alle Base
, aber eifrig laden bars, wenn zutreffend, also benutze ich folgende Abfrage:
SELECT b FROM Base b LEFT JOIN FETCH b.bars
Während dies funktioniert, es scheint zu generieren, eine Auswahl von N+1 problem für die Bar Personen:
Hibernate: /* SELECT b FROM Base b LEFT JOIN FETCH b.bars */ SELECT ...
Hibernate: /* load com.company.domain.Baz */ SELECT ...
Hibernate: /* load com.company.domain.Baz */ SELECT ...
Ist es möglich zu sagen, hibernate eifrig laden Sie eine Zuordnung für jedes element in der child-Sammlung ohne Rückgriff auf N+1 Wählt?
Habe ich versucht, etwas entlang der Linien von Sie die folgende Abfrage, die offensichtlich nicht funktionieren, da seine Sammlung:
SELECT b FROM Base b LEFT JOIN FETCH b.bars LEFT JOIN FETCH b.bars.baz
//Results in: illegal attempt to dereference collection [Foo.id.bars] with element property reference [baz]
Ich auch versucht, mit Hilfe IN(b.bars) bars
, und während dies ermöglicht es mir, Verweis auf die untergeordnete Sammlung, scheint es nicht zu eifrig laden Sie die bars-Sammlung, die ist mein Ziel.
Einer Erklärung, warum dies geschieht, wäre auch schön, da kann ich nicht scheinen, um es herauszufinden.
- Sind Sie mit "n+1 selects' - Problem für die Baz oder Bar ? Im stacktrace trace, die Sie zur Verfügung gestellt, es sieht aus wie der n+1 wählt, ist für die 'Baz'.
- Das ist richtig. Die Sammlung Bar-Entitäten wird mit Spannung korrekt geladen, wie erwartet, aber diese eifrigen laden offenbar Kräfte N wählt der Baz-Elemente.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Wenn Sie möchten, abrufen von Bar und Baz mit out (n+1) wählt bitte die folgende hql.
Sollte dies in nur einem sql.
Auch, wenn Sie nicht wollen, zu Holen, 'Baz', gerade die machen den Verein von Bar->Baz 'faul'.
JPA standardmäßig erzwingt 'begierig' Holen für "@OneToOne " und "@ManyToOne " Assoziationen. Also, Sie haben, um explizit zu machen, faul wie unten gezeigt.
Mein Ansatz (ich hatte eine begrenzte, stabile Anzahl von second-level-Einheiten)
Erste, erhalten Sie alle Bars in die Sitzung:
Danach, alle Bar-Einrichtungen werden in den cache und Ihre Abfrage wird in der Lage sein, um Ihnen den Zugang ohne weitere Elemente.
Ich würde sagen, dass die änderung des fetching-Strategie könnte in diesem Fall helfen. Die Dokumentation sagt:
http://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html_single/#performance-fetching-batch
Auszug:
Ich benutze es und es funktioniert gut. Im Fall ich bin paging und immer die Auswahl werden nur 20 Datensätze, batch-size="20" Super funktioniert. Wenn ich mehr als 20, noch die Aufrufe von DB verringert