hibernate - 如何避免 HQL 和 Criteria 中不必要的选择和联接

标签 hibernate optimization join hql criteria

我一直在尝试HQL条件的不同组合,但无法避免一些不必要的联接(两者都)以及一些不必要的选择(在标准中)。

在我们的场景中,应用程序实体之间存在@ManyToMany关系(导航是从段到应用程序)。

首先我尝试了这个标准:

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

它会产生以下 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没有从应用程序中选择属性(感谢“select s”部分),但仍然加入APPLICATIONS表,我认为是不必要的。我们怎样才能避免这种情况呢?

(顺便说一句,请注意,在 HQL 中我可以直接使用 app,而不是像 Criteria 中那样使用 app.getId())

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

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

非常感谢, 费兰

最佳答案

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

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

关于hibernate - 如何避免 HQL 和 Criteria 中不必要的选择和联接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61199581/

相关文章:

mysql - MySQL 中空表的左连接返回错误

hibernate - Spring + Hibernate 懒加载

hibernate - Grails -- 非法尝试取消引用 Hql 中的集合错误

java - Java中 "for"语句每次循环都计算循环条件吗?

c# - 逐像素碰撞优化

Django 多表继承和左外连接

MySQL在三张表上写连接

Java - Hibernate 调用 MySql 存储过程 - 警告消息

java - 插入另一个 IP 的命令被拒绝

c++ - 绘制多边形网格时 Opengl 性能问题