我的问题是 OneToOne 关联的休眠急切加载为每个空关系执行 +1 选择。
实体示例:
@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();
结果:如果所有蓝色侧实体都有一个红色侧,则一切正常,因此 hibernate 只对将检索到的实体执行一次对数据库的查询。
但是,如果蓝方实体没有关联的红方实体,则休眠尝试再次找到另一方。Hibernate sql 注释对每个空的 redSide 属性说 '/* load RedSide */ select ...'。
如何跳过第二个选择?
当延迟不是非常低时,就会出现实际问题。如果我尝试选择 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
第一行包含蓝色和红色面,但第二行仅包含蓝色面。所以hibernate必须知道相关的红方不存在。但是,在处理完所有结果行之后......
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