Il mio problema è che il caricamento in sospensione e impaziente dell'associazione OneToOne esegue la selezione +1 per ogni relazione nulla.Hibernate OneToOne (facoltativo = true) con FetchMode.JOIN tenta di riselezionare i valori nulli
Entity esempio:
@Entity
class SideBlue {
@Column(nullable = false)
private Integer timestamp;
@OneToOne(optional=true)
@JoinColumn(name="timestamp", referenceColumn="timestamp", insertable = false, updatable = false)
SideRed redSide;
}
@Entity
class SideRed {
@Column(nullable = false)
private Integer timestamp;
}
(Si tratta di uno schema di database legacy, in modo da modifiche del database non è consentito)
Query esempio:
CriteriaBuilder builder... CriteriaQuery query...
Root<SideBlue> root = query.from(SideBlue.class);
root.fetch(SideBlue_.sideRed, JoinType.LEFT);
entityManager().createQuery(query).getResultList();
Il risultato: Se tutto lato blu le entità hanno un lato rosso, tutto procede correttamente, quindi l'ibernazione esegue solo una query nel database per tutte le entità che verranno recuperate.
Tuttavia, se le entità del lato blu non hanno un'entità lato rosso associata, è necessario provare a trovare l'altra parte ancora una volta. Il commento Hibernate di sql dice '/ * carica RedSide */select ...' per ogni proprietà null redSide.
Come posso saltare questa seconda selezione?
Il problema pratico viene visualizzato quando la latenza non è estremamente bassa. Se provo a selezionare 1 milione di righe e 1/3 hanno "lati rossi" nulli, la latenza totale aggiunta è un problema reale.
EDIT:
Questo è il log di debug per la query
10:04:32.812 [main] DEBUG org.hibernate.loader.Loader - Result set row: 0
10:04:32.815 [main] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[SideBlue#1269721], EntityKey[SideRed#3620564]
10:04:32.833 [main] DEBUG org.hibernate.loader.Loader - Result set row: 1
10:04:32.833 [main] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[SideBlue#1269776], null
La prima riga contiene i lati blu e rosso, ma la seconda solo il lato blu. Quindi ibernare deve sapere che il lato rosso correlato non esiste. Ma, dopo che tutte le righe dei risultati vengono elaborate ...
10:04:33.083 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Resolving associations for [BlueSide#1269721]
10:04:33.084 [main] DEBUG org.hibernate.loader.Loader - Loading entity: [RedSide#component[timestamp]{timestamp=1338937390}]
10:04:33.084 [main] DEBUG org.hibernate.SQL - /* load RedSide */ select ...
! Nothing really loaded because the previous SQL return empty result set, again !
10:04:33.211 [main] DEBUG org.hibernate.loader.Loader - Done entity load
L'esempio è confuso, il lato che ha l'annotazione @JoinColumn su di esso è per definizione il proprietario della relazione. – Affe
Il mio errore. Io ridefinisco/migliorano la definizione dell'entità. È una versione semplificata della mia entità, ma penso che sia abbastanza. Il database non ha FK tra i timestamp di entrambi i lati. –