繁体   English   中英

如何加快一对多关联的Hibernate DML语句

[英]How to speedup Hibernate DML statements for one-to-many associations

我一直在尝试优化一个休眠应用程序,而我遇到的最大效率问题是它倾向于对子实体的简单操作执行n + 1个查询。 我已经能够通过在@Fetch(FetchMode.JOIN)上使用@Fetch(FetchMode.JOIN)来防止对选择操作的n + 1查询,但这不会影响更新/插入/删除查询。 以下是相关实体和属性的示例:

// parent entity for Mean and Covariance entities
@Entity
@DynamicInsert
@Table(name = "belief")
public class Belief implements Serializable, Cloneable {

    // surrogate key
    @Id
    @GeneratedValue
    @Column(name = "belief_id", unique = true, insertable = false, updatable = false)
    private Integer id;

    // other properties...

    @Cascade(org.hibernate.annotations.CascadeType.ALL)
    @OneToMany(mappedBy = "pk.beliefId", orphanRemoval = true, fetch = FetchType.LAZY)
    private List<Mean> means = new ArrayList<>();

    @Cascade(org.hibernate.annotations.CascadeType.ALL)
    @OneToMany(mappedBy = "pk.beliefId", orphanRemoval = true, fetch = FetchType.LAZY)
    private List<Covariance> covariances = new ArrayList<>();

}

@Entity
@DynamicInsert
@Table(name = "mean")
public class Mean implements Serializable, Cloneable {

    // composite key
    @EmbeddedId
    private MeanPK pk = new MeanPK(this);

    @Fetch(FetchMode.JOIN)
    @ManyToOne(fetch = FetchType.LAZY, cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH })
    @JoinColumn(name = "belief_id", insertable = false, nullable = false, updatable = false)
    private Belief belief;

    // other properties...
}

@Entity
@DynamicInsert
@Table(name = "covariance")
public class Covariance implements Serializable, Cloneable {

    // composite key
    @EmbeddedId
    private CovariancePK pk = new CovariancePK(this);

    @Fetch(FetchMode.JOIN)
    @ManyToOne(fetch = FetchType.LAZY, cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH })
    @JoinColumn(name = "belief_id", insertable = false, nullable = false, updatable = false)
    private Belief belief;

    // other properties...
}

所以当我执行session.delete(belief); ,日志显示针对每个协方差执行单独的delete语句,并表示信念实体可能已引用。 这是日志的示例:

Hibernate: select belief0_.belief_id as belief_i1_0_0_, belief0_.after_comb as after_co2_0_0_, belief0_.description as descript3_0_0_, belief0_.name as name4_0_0_, belief0_.project_id as project_7_0_0_, belief0_.type as type5_0_0_, belief0_.version as version6_0_0_ from belief belief0_ where belief0_.belief_id=?
Hibernate: select covariance0_.belief_id as belief_i1_0_0_, covariance0_.belief_id as belief_i1_1_0_, covariance0_.col_variable_id as col_vari2_1_0_, covariance0_.row_variable_id as row_vari3_1_0_, covariance0_.belief_id as belief_i1_1_1_, covariance0_.col_variable_id as col_vari2_1_1_, covariance0_.row_variable_id as row_vari3_1_1_, covariance0_.variance as variance4_1_1_, covariance0_.version as version5_1_1_, variable1_.variable_id as variable1_5_2_, variable1_.definition as definiti2_5_2_, variable1_.description as descript3_5_2_, variable1_.name as name4_5_2_, variable1_.project_id as project_6_5_2_, variable1_.version as version5_5_2_, variable2_.variable_id as variable1_5_3_, variable2_.definition as definiti2_5_3_, variable2_.description as descript3_5_3_, variable2_.name as name4_5_3_, variable2_.project_id as project_6_5_3_, variable2_.version as version5_5_3_ from covariance covariance0_ inner join variable variable1_ on covariance0_.col_variable_id=variable1_.variable_id inner join variable variable2_ on covariance0_.row_variable_id=variable2_.variable_id where covariance0_.belief_id=?
Hibernate: select means0_.belief_id as belief_i1_0_0_, means0_.belief_id as belief_i1_2_0_, means0_.variable_id as variable2_2_0_, means0_.belief_id as belief_i1_2_1_, means0_.variable_id as variable2_2_1_, means0_.mean as mean3_2_1_, means0_.swept as swept4_2_1_, means0_.version as version5_2_1_, variable1_.variable_id as variable1_5_2_, variable1_.definition as definiti2_5_2_, variable1_.description as descript3_5_2_, variable1_.name as name4_5_2_, variable1_.project_id as project_6_5_2_, variable1_.version as version5_5_2_ from mean means0_ inner join variable variable1_ on means0_.variable_id=variable1_.variable_id where means0_.belief_id=?
Hibernate: delete from covariance where belief_id=? and col_variable_id=? and row_variable_id=? and version=?
Hibernate: delete from covariance where belief_id=? and col_variable_id=? and row_variable_id=? and version=?
Hibernate: delete from mean where belief_id=? and variable_id=? and version=?
Hibernate: delete from mean where belief_id=? and variable_id=? and version=?
Hibernate: delete from mean where belief_id=? and variable_id=? and version=?
Hibernate: delete from mean where belief_id=? and variable_id=? and version=?
Hibernate: delete from mean where belief_id=? and variable_id=? and version=?
Hibernate: delete from belief where belief_id=? and version=?

对于此n + 1问题,我已经进行了大量的搜索工作,并且只找到了针对选择操作的解决方案,而没有级联插入/更新/删除操作。 有谁知道如何解决和优化它? 谢谢!

Hibernate将实体状态转换转换为DML语句,这就是为什么每个删除的实体都有一个DELETE语句的原因。

不应该使用EAGER fetching ,因为基于查询的获取策略始终更加灵活并且可以产生最佳性能。 关联应为LAZY并且您应使用JOIN FETCH指令仅检索每个特定业务案例所需的关系。

您还应该启用以下语句的批处理:

如果您有写密集型应用程序,则可以使用具有批量UPDATE/DELETE HQL/JPQL支持的批量语句。

您基本上已经处在预期的休眠魔术已经结束一段时间并在OR-Mapping现实中结束的时候了。

您可以从OneToMany中删除FetchType.Lazy,因为那是默认值。 FetchType.Eager将是克服select语句的n + 1问题的方法。 您也没有这样做(或者说您将hibernate和jpa的东西混在一起,不确定在那种情况下什么会赢)。 您为什么要批量删除? 如果是,则这样做,但是不要期望休眠为您做出决定。 请记住,通过ID集合进行删除可能不会触发级联和孤立删除。 如果您期望该列表中有大量条目,那么现在是重构映射的时候了。

!!但最重要!!!

您的映射中有很多东西,这似乎会对性能带来更高的负面影响,并且在某些情况下会导致意外的行为。 对我来说,您似乎想对某件事进行性能优化,这不是最大的问题。 只要您的删除没有性能问题,请不要执行任何操作。

  • 混合两个读取系统
  • 级联使用率很高-为什么要做出此决定。 他们的背后真的是一个思考过程吗? 或为您解决了一个问题,可以通过手动处理以更清洁的方式解决。
  • 是否存在不能由简单的Long ID处理的EmbeddedId内容的特定原因? 对我来说似乎有点过头了。
  • 我不怀疑JoinColumn可插入等东西。 我只是希望背后有一个原因。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM