I am trying to cascade persistence on a large object graph using JPA. For example (my object graph is slightly larger, but close enough):
@Entity @Table(name="a") public class A { private long id; @OneToMany(cascade = CascadeType.ALL, mappedBy = "a") private Collection<B> bs; } @Entity @Table(name="b") public class B { private long id; @ManyToOne private A a; }
So I'm trying to save A, which has a collection of 100+ B. The code is just
em.persist(a);
The problem is that she is SLOW. My save takes about 1300 ms. I looked at the generated SQL and is terribly inefficient. Something like that:
select a_seq.nextval from dual; select b_seq.nextval from dual; select b_seq.nextval from dual; select b_seq.nextval from dual; ... insert into a (id) values (1); insert into b (id, fk) values (1, 1); insert into b (id, fk) values (2, 1); insert into b (id, fk) values (3, 1); ...
Currently using toplink as a persistence provider, but I also tried eclipselink and hibernate. Backend - Oracle 11g. The problem is how sql is compiled. Each of these operations is performed discretely, rather than in bulk, so if there is a network latency of even 5 ms between my application server and the db server, performing 200 discrete operations adds 1 second. I tried to increase the highlight in my sequences, but that helps a bit. I also tried directly JDBC as a batch statement:
for...{ statement = connection.prepareStatement(sql); statement.addBatch(); } statement.executeBatch();
For my datamodel it takes about 33 ms, made as a direct JDBC batch. Oracle itself takes 5 ms for over 100 inserts.
Is there a way to make JPA (I'm stuck with 1.0 right now ...) faster without delving into vendor-specific things like sleep mode insertion?
Thanks!