JPA中显式和隐式JOIN有什么区别? (性能)

时间:2018-03-27 08:57:43

标签: java jpa jpa-2.0 jpql

这些天我读到JPA。我了解到可以在JPQL中使用explicitimplicit JOIN

明确加入

  

em.createQuery(“SELECT b.title,p.name FROM Book b JOIN b.publisher   P”)getResultList();

隐式联接

  

em.createQuery(“SELECT b.title,b.publisher.name FROM Book   B”)getResultList();

这些示例的来源:link

我的问题是: explicitimplict之间的效果是否存在差异?

更新

我已经阅读了你写的@MatteoBaldi和@Kayaman的内容,我已经完成了一些测试,我想与你分享结果。

我创建了两个实体:studentscourse,我有manyToOne(许多学生参加一门课程)。我已使用EcpliseLink JPA的实施。

查询=从课程中选择学生和虚拟文件,执行方案:

  1. manyToOne(defaultFetch - > eager),隐式JOIN。 结果:执行所有工作的单个SQL查询。
  2. manyToOne(Fetch - > lazy),隐式JOIN。 结果:与1相同的SQL查询。
  3. manyToOne(defaultFetch - > eager),显式JOIN。 结果:与1相同的SQL查询。
  4. manyToOne(Fetch - > lazy),显式JOIN。 结果:与1相同的SQL查询。
  5. 所以在我的测试环境(EclipseLink,..)中,我有从我的JPQL查询生成的相同SQL查询。所以我可以说性能是相同的(当然,我在测试条件中再次说,我希望有人可以确认/纠正我的结果并制定一般规则。

3 个答案:

答案 0 :(得分:2)

它们的解析方式不同,因此根据查询,实体关系和其他类似的东西,它们最终可能会成为不同的SQL查询。理想情况下,只要JPQL查询执行相同的操作就应该没有区别,但it doesn't always work that way

推荐的方法是使用显式连接,这具有其他优点,例如在惰性关系上指定JOIN FETCH。这个问题在性能上有点过分,显然如果其中一个性能更高但结果相同,就没有理由使用较慢的那个。

启用SQL日志记录以查看生成的查询是验证应用程序是否正在进行所需查询的好方法,无论您使用哪种语法。您不能仅仅依赖于JPQL,您需要了解和理解您的数据库,这样您才能使用"混淆层" as a_horse_with_no_name喜欢调用ORM框架;)

答案 1 :(得分:1)

他们应该是相同的,但实际上它主要取决于底层数据库。在当前环境中测试性能的一种快速方法是启用SQL日志记录,跟踪jpql被转换为的本机查询,并直接使用SQL客户端进行尝试。

答案 2 :(得分:1)

通常,我总是显式地列出每个JOIN。主要目的是要更清楚地了解查询的功能以及查询的方式,使用更可预测的SQL以及将来查询的更改。

但是我可以举一个例子,其中隐式JOIN比显式JOIN具有更高的性能,即使在大多数情况下,这种性能提升也是很小的,而且个人不承担风险(我稍后会解释什么风险)。

想象一下,您正在尝试将同一本书的所有书籍归为一组。通过显式 JOIN,这是JPQL:

 SELECT count(publisher.id) 
 FROM FROM Book b
 JOIN b.publisher publisher
 WHERE publisher.id = 1
 GROUP by publisher.id

此查询是可读的,没有任何重复,并且此查询中的任何更改(例如添加另一个WHERE条件)都将按预期保持生成的SQL。

现在,以隐式加入:

 SELECT count(b.publisher.id) 
 FROM FROM Book b
 WHERE b.publisher.id = 1
 GROUP by b.publisher.id

我们by b.publisher.id重复了三遍。如果添加其他条件,则存在Hibernate的JPQ解释会更改生成的SQL的风险,如Kayaman answer所述进行不必要的JOIN。

但是具有隐式JOIN的JPQL不会对生成的SQL进行额外的JOINpublisher表的操作,因为他可以使用id中的published_id:< / p>

 SELECT Count(b.published_id) AS col_0_0_ 
 FROM   Book b
 WHERE  b.published_id = ? 
 GROUP  BY b.published_id

以及带有额外JOIN的SQL显式JOIN:

 SELECT Count(published.id) AS col_0_0_ 
 FROM   Book b
 INNER JOIN published published1_ 
           ON b.published_id = published1_.id 
 WHERE  published_id = ? 
 GROUP  BY published_id

但这仅在来自publisher的外键在book侧的情况下发生。在这种情况下是正确的方法,但是在某些映射中外键可能位于表的任何一侧,因此显式和隐式JPQL查询可以生成相同 SQL。

根据我的经验,显式JOIN总是一个更好的选择。 Hibernate并不总是理解在同一查询上重复的相同隐式JOIN是同一JOIN的一部分,从而创建了未优化/奇怪的SQL。