如何避免在HQL和Criteria中不必要的选择和连接

时间:2012-05-19 12:16:29

标签: hibernate optimization join hql criteria

我一直在尝试 HQL 标准的不同组合,但我无法避免一些不必要的加入(两者都有)和一些不必要的选择(在Criteria中)。

在我们的方案中,我们在细分应用程序实体之间存在 @ManyToMany 关系(导航是从细分到应用程序)。

首先,我尝试了标准

Application app = ...
List<Segment> segments = session.createCriteria(Segment.class)
    .createCriteria(Segment.APPLICATIONS)
    .add(Restrictions.idEq(app.getId()))
    .list();

Wich产生这个SQL:

select
    this_.id as id1_1_,
    this_.description as descript2_1_1_,
    this_.name as name1_1_,
    applicatio3_.segment_id as segment1_1_,
    applicatio1_.id as app2_,               <==== unnecessary APPLICATIONS columns
    applicatio1_.id as id7_0_,
    applicatio1_.name as name7_0_,
    applicatio1_.accountId as accountId7_0_,
    applicatio1_.applicationFlags as applicat5_7_0_,
    applicatio1_.description_ as descript6_7_0_,
from
    SEGMENTS this_ 
inner join
    SEGMENTS_APPLICATIONS applicatio3_ 
        on this_.id=applicatio3_.segment_id 
inner join                                       <==== unnecessary join
    APPLICATIONS applicatio1_ 
        on applicatio3_.app_id=applicatio1_.id 
where
    applicatio1_.id = ?

如您所见, Criteria选择APPLICATIONS 中的列,我不想选择它们。我还没有找到办法(可能吗?)。此外,它加入APPLICATIONS ,我认为没有必要,因为应用程序ID已经在连接表SEGMENTS_APPLICATIONS中(HQL也是如此)。

(另外一个疑问,我想知道直接使用应用程序的限制,而不是app.getId()。正如您将看到的,我可以在查询的HQL版本中执行此操作)

由于我无法限制选择部分(我不需要应用程序属性),我使用“select”子句尝试了 HQL

Application app = ...
List<Segment> segments = session.createQuery(
    "select s from Segment s join s.applications as app where app = :app")
    .setParameter("app", app)
    .list();

产生:

select
    segment0_.id as id1_,
    segment0_.description as descript2_1_,
    segment0_.name as name1_,
from
    SEGMENTS segment0_ 
inner join
    SEGMENTS_APPLICATIONS applicatio1_ 
        on segment0_.id=applicatio1_.segment_id 
inner join                                        <==== unnecessary join
    APPLICATIONS applicatio2_ 
        on applicatio1_.app_id=applicatio2_.id 
where
    applicatio2_.id=? 

你可以看到 HQL没有从Application 中选择属性(感谢“select s”部分),但是仍然加入了APPLICATIONS 表,我认为没必要。我们怎么能避免这种情况?

(作为旁注,注意在HQL中我可以直接使用app,而不是像Criteria中那样使用app.getId())

你能帮我找到一种方法来避免Criteria中的“选择”以及Criteria和HQL中不必要的“连接”吗?

(这个例子是@ManyToMany,但我认为它也适用于@OneToMany以及@ManyToOne和@OneToOne,即使使用fetch = LAZY)。

非常感谢, 费兰

1 个答案:

答案 0 :(得分:6)

使用条件时,其他选定的列来自长期存在的bug in Hibernate。 AFAIK,避免它的唯一方法是使用HQL或JPA2标准API。

另一个问题也标示为a bug,但影响较小,我对此并不在意。