私の問題は、OneToOneアソシエーションの休止状態の積極的な読み込みが、null関係ごとに+1selectを実行することです。
エンティティの例:
@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;
}
(これはレガシーデータベーススキーマであるため、データベースの変更は許可されていません)
クエリの例:
CriteriaBuilder builder... CriteriaQuery query...
Root<SideBlue> root = query.from(SideBlue.class);
root.fetch(SideBlue_.sideRed, JoinType.LEFT);
entityManager().createQuery(query).getResultList();
結果:すべての青い側のエンティティに1つの赤い側がある場合、すべてが正しく実行されるため、Hibernateは、取得されるエンティティに対してデータベースに対して1つのクエリのみを実行します。
ただし、青い側のエンティティに赤い側のエンティティが関連付けられていない場合、休止状態はもう一度反対側を見つけようとします。Hibernate sqlコメントは、nullのredSideプロパティごとに「/*ロードRedSide* /select...」と言っています。
この2番目の選択をスキップするにはどうすればよいですか?
実際の問題は、レイテンシが極端に低くない場合に発生します。100万行を選択しようとして、1/3にヌルの「赤い面」がある場合、追加される合計レイテンシーは実際の問題です。
編集:
これはクエリのデバッグログです
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
最初の行には青と赤の面が含まれていますが、2番目の行には青の面のみが含まれています。したがって、休止状態は、関連する赤い面が存在しないことを知っている必要があります。しかし、すべての結果行が処理された後...
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