【问题标题】:Needless Left Outer Join Created on FK's using JPA/Hibernate使用 JPA/Hibernate 在 FK 上创建的不必要的左外连接
【发布时间】:2018-05-15 21:06:40
【问题描述】:

我有一个实体,例如:

@Entity
class Brand {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(nullable = false, columnDefinition = "BIGINT")
  private Long id;

  @NotNull(message = NOT_NULL_CODE)
  @Size(min = 5, max = 150, message = SIZE_CODE)
  @Column(nullable = false, length = 150)
  private String name;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "organization_id", nullable = false)
  @JsonBackReference("organization-brands")
  private Organization organization;

  // getters and setters
}

我的存储库定义了以下内容:

Page<Brand> findAllByOrganization(Organization organization, Pageable pageable);

这会产生以下查询:

select
        brand0_.id as id1_1_,
        brand0_.name as name2_1_,
        brand0_.organization_id as organiza3_1_
    from
        brand brand0_ 
    left outer join
        organization organizati1_ 
            on brand0_.organization_id=organizati1_.id 
    where
        organizati1_.id=? limit ?

我想知道为什么会创建一个left outer join?我想可能是因为organization_id 是选择的一部分,所以我创建了一个仅包含nameid 列的DTO 投影,但仍然包括left outer join。我找到了this bug report,但它的移动为零。

这与我有关的原因是因为left outer join 平均增加了 200 毫秒的查询时间。我还没有进行任何基准测试来确定这是否会随着更多数据行而呈指数增长。但是对于我当前的数据集,它是 200 毫秒。哎呀。

【问题讨论】:

  • 可能是因为 Hibernate/JPA 需要引用来获取组织对象。因为你的 Brand 对象有一个 Organization 对象,不是很长的 fk
  • 这也是我们的情况,我们使用 QueryDSL 库是为了更好地控制 jpa 查询,尤其是在运行返回 DTO 的小投影而不是完整实体的查询时。
  • 可能与stackoverflow.com/a/17987718/1356423有关。试试@ManyToOne(fetch = FetchType.LAZY, optional = false)。如果没有这个,我猜 Hibernate 必须检查表以查看是否设置代理或 null。
  • @MarcosVasconcelos 我很确定查询实体可能就是这种情况。但是使用 DTO 投影,我什至不要求组织。它不在选择中,它仍在添加该连接。
  • 你查询方法返回Page<Brand>。这个 DTO 在哪里?

标签: java hibernate spring-boot spring-data spring-data-jpa


【解决方案1】:

这很可能与:

http://stackoverflow.com/a/17987718/1356423

从列定义上的nullable = false 来看,这种关系看起来是非可选的,因此请尝试注释为@ManyToOne(fetch = FetchType.LAZY, optional = false)

如果没有optional = false,Hibernate 必须检查关联表以查看是否为关联的组织设置代理或 null:因此加入。

【讨论】:

    【解决方案2】:

    假设组织类 PK 被命名为 id 那么

    Page<Brand> findAllByOrganizationId(String organizationId, Pageable pageable);
    

    应该做你想做的

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-08
      • 1970-01-01
      • 2013-04-02
      • 1970-01-01
      • 1970-01-01
      • 2011-06-26
      • 1970-01-01
      • 2011-01-25
      相关资源
      最近更新 更多