【问题标题】:Avoiding outer joins across tables when using joined inheritance with Spring Data JPA使用 Spring Data JPA 的连接继承时避免跨表的外部连接
【发布时间】:2013-05-14 10:44:44
【问题描述】:

考虑 Spring Data JPA (+ Hibernate) 应用程序中的以下类:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = "person")
public class Person { }

@Entity
@Table(name = "customer")
public class Customer extends Person { }

@Entity
@Table(name = "employee")
public class Employee extends Person { }

@Entity
@Table(name = "manager")
public class Manager extends Employee { }

public interface IPersonRepository extends JpaRepository<Person, Long> { }
public interface ICustomerRepository extends JpaRepository<Customer, Long> { }
public interface IEmployeeRepository extends JpaRepository<Employee, Long> { }

我最常见的用例涉及调用以下方法(继承自JpaRepository):

IPersonRepository.findAll();

每当调用此方法时,Hibernate 都会发出以下 SQL 查询:

select
    person0_.id as id1_3_,
    person0_.version as version2_3_,
    person0_.first_name as first3_3_,
    person0_.last_name as last4_3_,
    person0_1_.customer_code as customer1_0_,
    person0_2_.employee_code as employee1_1_,
    person0_2_.manager_id as manager3_1_,
    case
        when person0_3_.id is not null then 3
        when person0_1_.id is not null then 1
        when person0_2_.id is not null then 2
        when person0_.id is not null then 0
    end as clazz_
from
    person person0_
left outer join
    customer person0_1_
on person0_.id=person0_1_.id
left outer join
    employee person0_2_
on person0_.id=person0_2_.id
left outer join
    manager person0_3_
on person0_.id=person0_3_.id;

每当执行此查询时,我只对Person 类中的公共字段感兴趣,因此我发现左外连接无用。

问题是在我们的实际应用中,有EmployeeCustomer这样的8个子类,每个子表有数百万条记录,导致父表查询运行很慢。

在这种情况下,有没有办法避免跨表的外部连接?请注意,我已尝试使用 DiscriminatorColumn 方法,并且在这种情况下仍会执行连接(使用 Hibernate 时)。我还在所有可能的组合中尝试了实体类上特定于 Hibernate 的 Polymorphism 注释,并且仍然执行外部连接。

Spring Data JPA version: 1.2.0
Hibernate version: 4.2.1

【问题讨论】:

    标签: hibernate inheritance jpa spring-data-jpa joined-subclass


    【解决方案1】:

    经过多日尝试解决这个问题,我得出以下结论:

    1. 在这种情况下,无法强制 Hibernate 4.x(和 3.x)不执行外连接。
    2. 无法强制 TopLink Essentials (v2.1-60) 和 OpenJPA (v2.2.2) 的最新可用版本也不执行外连接。
    3. 可以使用最新可用版本的 EclipseLink (v2.5.0) 避免外部连接。但是,EclipseLink 需要上面显示的类层次结构的鉴别器列,即使 Hibernate 和 OpenJPA 不需要。到目前为止,我一直无法找到避免将鉴别器列与 EclipseLink 一起使用的方法。

    我想我将不得不等待 JPA 规范更改或满足我当前要求的 JPA 实现可用。

    【讨论】:

    • 你有一个关于如何避免 Eclipselink 中的外连接的例子吗?
    • 是通过QueryHints吗?
    【解决方案2】:

    不是直接回答您的问题,而是:

    您可以用@OneToOne 组合替换此继承。

    表格结构几乎保持不变。您可以查询具体类型而无需您想要避免的 JOIN。

    @Entity
    @Table(name = "personDetails")
    public class PersonDetails { }
    
    @Entity
    @Table(name = "customer")
    public class Customer {
    
       @OneToOne
       PersonDetails personDetails;
     }
    
    @Entity
    @Table(name = "employee")
    public class Employee {
    
       @OneToOne
       PersonDetails personDetails;
    
     }
    
    @Entity
    @Table(name = "manager")
    public class Manager {
    
       @OneToOne
       PersonDetails personDetails;
    
     }
    

    刚刚将 Person 的名称更改为 PersonDetails,以便在此上下文中使用更好的名称。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-30
      • 2010-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-17
      • 2020-08-30
      • 1970-01-01
      相关资源
      最近更新 更多