与共享主键的OneToOne关系生成n + 1个选择;任何解决方法? [英] OneToOne relationship with shared primary key generates n+1 selects; any workaround?
问题描述
在通过命名查询进行人员选择时,如:
from Person p where Hibernate / JPA生成两个select查询,一个在Person表中,另一个在Person表中,另一个在Person表中。
主键)。
上面的示例非常简单,并且不会导致任何性能问题,因为查询只返回一个结果。现在,假设
Person
与其他实体(所有共享n
OneToOne关系(全部非强制) c $ c> Person
如果我错了,请纠正我,但运行
选择
对Person进行查询,返回r
行,会导致(n + 1)* r
选择由Hibernate生成,即使关联是 lazy 。
是否有解决此潜在性能灾难的方法(除了不使用共享主键)?感谢您提出您的所有想法。
解析方案
设想关系数据库中的2个表,例如人员和帐单。在这些实体之间定义了一个(非强制的)OneToOne关联, 从非概念上讲,非强制OneToOne默认情况下,Hibernate必须命中数据库才能知道关联是否为 [...] 现在考虑我们的B类有 在加载B之后,您可以调用 但现在想象你的 所以,默认情况下不可能。 是否有解决此潜在性能灾难的方法(除了根本不使用共享主键)?感谢您的所有想法。 问题不在于共享主键,有或没有共享主键,您会得到它的问题是可空 OneToOne。 第一选项:使用字节码检测(请参阅文档下面)和 no-proxy 获取: 第二选项:使用假的 第三选项:使用 Imagine 2 tables in a relational database, e.g. Person and Billing. There is a (non-mandatory) OneToOne association defined between these entities, and they share the Person primary key (i.e. PERSON_ID is defined in both Person and Billing, and it is a foreign key in the latter). When doing a select on Person via a named query such as: Hibernate/JPA generates two select queries, one on the Person table and another on the Billing table. The example above is very simple and would not cause any performance issues, given the query returns only one result. Now, imagine that Correct me if I'm wrong, but running a Is there a workaround for this potential performance disaster (other than not using a shared primary key at all)? Thank you for all your ideas. Imagine 2 tables in a relational database, e.g. Person and Billing. There is a (non-mandatory) OneToOne association defined between these entities, Lazy fetching is conceptually not possible for non-mandatory OneToOne by default, Hibernate has to hit the database to know if the association is [...] Now consider our class B has
one-to-one association to C Right after loading B, you may call
But now imagine your So the resume: if your B->C mapping
is mandatory ( So, not possible... by default. Is there a workaround for this potential performance disaster (other than not using a shared primary key at all)? Thank you for all your ideas. The problem is not the shared primary key, with or without shared primary key, you'll get it, the problem is the nullable OneToOne. First option: use bytecode instrumentation (see references to the documentation below) and no-proxy fetching: Second option: Use a fake Third option: Eager load the Billing using a 这篇关于与共享主键的OneToOne关系生成n + 1个选择;任何解决方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
null
。来自这个旧维基页面的更多细节:
关于延迟加载的一些解释(一对一)
一对一的关联到C
class B {
private C cee;
public C getCee(){
return cee;
}
public void setCee(C cee){
this.cee = cee;
}
}
class C {
//真的不重要
}
getCee()
来获得C.但是, b $ b getCee()
是您的类
的一种方法,Hibernate无法控制它。
Hibernate不知道某人
何时会调用 getCee()
。
意味着Hibernate必须在
数据库中加载B时将
适当的值放入 cee
属性中。如果为
C
启用了代理,Hibernate可以将一个尚未加载的C代理
对象,但
将被加载当有人使用它时。
这为
一对一
提供了延迟加载。
B
对象may或
可能没有关联 C
( constrained =false
)。当特定 B
没有<$ c $时,
getCee()
ç> C ?空值。但请记住,
Hibernate在设置 B
时必须设置正确的
cee值(因为它不知道何时某人
将会调用 getCee()
)。代理不
在这里帮助,因为代理本身在
中已经是非空对象。所以简历:如果你的B-> C映射
是强制性的( constrained = true
),
Hibernate将使用C
的代理,导致延迟初始化。但是
,如果你允许B没有C,Hibernate
只是在加载B时检查C在
的存在。但是一个SELECT到
检查存在是低效的
因为相同的SELECT可能不仅仅是
检查存在,而是加载整个
对象。所以懒加载消失。
@OneToOne(fetch = FetchType.LAZY)
@ org.hibernate.annotations.LazyToOne(org.hibernate.annotations.LazyToOneOption.NO_PROXY)
ManyToOne(fetch = FetchType.LAZY)
。这可能是最简单的解决方案(据我所知,推荐的解决方案)。但我没有用共享的PK来测试它。
$ b
引用
a>
from Person p where p.id = :id
Person
has n
OneToOne relationships (all non-mandatory) with other entities (all sharing the Person
primary key).select
query on Person, returning r
rows, would result in (n+1)*r
selects being generated by Hibernate, even if the associations are lazy.
null
or not. More details from this old wiki page:
Some explanations on lazy loading (one-to-one)
class B {
private C cee;
public C getCee() {
return cee;
}
public void setCee(C cee) {
this.cee = cee;
}
}
class C {
// Not important really
}
getCee()
to obtain C. But look,
getCee()
is a method of YOUR class
and Hibernate has no control over it.
Hibernate does not know when someone
is going to call getCee()
. That
means Hibernate must put an
appropriate value into "cee
"
property at the moment it loads B from
database. If proxy is enabled for
C
, Hibernate can put a C-proxy
object which is not loaded yet, but
will be loaded when someone uses it.
This gives lazy loading for
one-to-one
. B
object may or
may not have associated C
(constrained="false"
). What should
getCee()
return when specific B
does not have C
? Null. But remember,
Hibernate must set correct value of
"cee" at the moment it set B
(because it does no know when someone
will call getCee()
). Proxy does not
help here because proxy itself in
already non-null object.constrained=true
),
Hibernate will use proxy for C
resulting in lazy initialization. But
if you allow B without C, Hibernate
just HAS TO check presence of C at the
moment it loads B. But a SELECT to
check presence is just inefficient
because the same SELECT may not just
check presence, but load entire
object. So lazy loading goes away.
@OneToOne( fetch = FetchType.LAZY )
@org.hibernate.annotations.LazyToOne(org.hibernate.annotations.LazyToOneOption.NO_PROXY)
ManyToOne(fetch=FetchType.LAZY)
. That's probably the most simple solution (and to my knowledge, the recommended one). But I didn't test this with a shared PK though.join fetch
.Related question
References