Well ! I think i pointed out a HUGE performance issue with mapped-by attribute (yeah again :( ).
Here is the test case :
1- Create 100 000 entities with for each 1 entity with @OneToOne(mappedBy attribute)
2- Retrieve only 10 000 for testing
3- Wait ... On my AMD FX 8350, it took 60s
Now, go the MyEntity class and remove "mapped-by".
You obtain 1 second max of query fetch.
So my performance issue in my application is more due to that problem than the left join one. ( Note : The left join index pb still exists, i will test your optimisation disabled latter )
So, the test case, enjoy :
The entity :
import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.OneToOne; @Entity public class MyEntity { @Id private String name; public MyEntity(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } private MyEntityChild entityChild = null; @OneToOne(targetEntity = MyEntityChild.class, cascade = CascadeType.ALL,mappedBy = "myEntity") // Test by adding / remove "mappedBy" public MyEntityChild getEntityChild() { return entityChild; } public void setEntityChild(MyEntityChild entityChild) { this.entityChild = entityChild; } @Entity public static class MyEntityChild { @Id private String name; private MyEntity myEntity; public MyEntity getMyEntity() { return myEntity; } public void setMyEntity(MyEntity myEntity) { this.myEntity = myEntity; } MyEntityChild(String name) { this.name = name; } } }
The test case :
public class ObjectDbTest { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("objectdb:$objectdb/db/test.tmp;drop"); EntityManager em = null; em = emf.createEntityManager(); if (!em.getTransaction().isActive()) { em.getTransaction().begin(); } // Write 100 000 entities with 1 child for each for (int i=0;i<100000;++i) { MyEntity e1 = new MyEntity("parent" + i); MyEntityChild child2 = new MyEntityChild("child" +i); child2.setMyEntity(e1); e1.setEntityChild(child2); em.merge(e1); } em.getTransaction().commit(); em.clear(); em.close(); em = emf.createEntityManager(); Long start = new Date().getTime(); TypedQuery<MyEntity> query = em.createQuery("SELECT m FROM MyEntity m", MyEntity.class); // Retrieve only 10 000 List <MyEntity> entities = query.setMaxResults(10000).getResultList(); Long end = new Date().getTime(); Long duration = (end - start) / 1000; System.out.println("Duration : " + duration + " seconds"); em.close(); emf.close(); // Be sure we retrieve child if (entities.get(0).getEntityChild() == null) { System.out.println("FAILED TO FETCH !"); } }
Regards,
Xirt