title: How to speedup Hibernate DML statements for one-to-many associations
body: <p>I have been trying to optimize a hibernate application and one of the biggest problems I have faced with Hibernates efficiency is its tendency to execute n+1 queries for a simple crud operation with child entities. I have been able to prevent n+1 queries for select operations by using <code>@Fetch(FetchMode.JOIN)</code> on the child entity (many-to-one side), but that does not affect update/insert/delete queries. Here is a sample of the relevant entities and properties:</p>
  
  <pre><code>// 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&lt;Mean&gt; means = new ArrayList&lt;&gt;();
  
      @Cascade(org.hibernate.annotations.CascadeType.ALL)
      @OneToMany(mappedBy = "pk.beliefId", orphanRemoval = true, fetch = FetchType.LAZY)
      private List&lt;Covariance&gt; covariances = new ArrayList&lt;&gt;();
  
  }
  
  @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...
  }
  </code></pre>
  
  <p>So when I execute <code>session.delete(belief);</code>, the logs show that a separate delete statement is executed for every covariance and mean that the belief entity may have referenced. Here is an example of the log:</p>
  
  <pre><code>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=?
  </code></pre>
  
  <p>I have done a good amount of googling for a fix for this n+1 issue, and I have only found solutions for select operations, and not cascading insert/update/delete operations.
  Does anyone have an idea as to how this can be fixed and optimized?
  Thanks!</p>