【问题标题】:How to avoid unnecessary selects and joins in HQL and Criteria如何避免 HQL 和 Criteria 中不必要的选择和连接
【发布时间】:2012-05-19 12:16:29
【问题描述】:

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

在我们的场景中,SegmentApplication 实体之间存在 @ManyToMany 关系(导航是从 Segment 到 Applications)。 p>

首先我尝试了这个标准

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 版本的查询中做到这一点)

由于我无法限制选择部分(我不需要应用程序属性),所以我尝试了这个 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 中不必要的“join”?

(此示例适用于 @ManyToMany,但我认为 @OneToMany 以及 @ManyToOne 和 @OneToOne 也会发生这种情况,即使 fetch = LAZY 也是如此)。

非常感谢, 费兰

【问题讨论】:

    标签: hibernate optimization join hql criteria


    【解决方案1】:

    使用 Criteria 时额外选择的列来自长期存在的bug in Hibernate。 AFAIK,避免它的唯一方法是使用 HQL,或 JPA2 标准 API。

    另一个问题也被标记为a bug,但它的影响较小,我不会太在意。

    【讨论】:

    • 哇,非常感谢。一个长期存在的错误?我不敢相信他们还没有修好它。仅仅因为 HQL 有解决方法?
    • 我也不敢相信 :-( OTOH,它是开源软件,他们可能正忙于实施新的 JPA2 标准实施,这可能比旧的专有 API 更受欢迎。
    • 哦,那么您会建议我们开始使用 JPA2 而不是旧的 Criteria API 吗?两者可以混合吗? (只是为了避免重构旧代码)。
    • 我不推荐任何东西 :-) 但是如果我必须从头开始一个新项目,我会使用标准的 JPA API 和新的 Criteria API。
    • @JB nizet 提到这个错误让我省了很多关于为什么条件查询无用地离开外部连接到链接表并使查询减慢一个数量级的问题。 HQL 重写它是!
    猜你喜欢
    • 2011-02-25
    • 1970-01-01
    • 2012-09-30
    • 2015-09-27
    • 1970-01-01
    • 1970-01-01
    • 2014-08-29
    • 2011-09-08
    • 2020-10-02
    相关资源
    最近更新 更多