Steve Ebersole commented on New Feature HHH-5187

The concern over what Hibernate does here today is essentially a question of context. Hibernate creates and caches a load-for-merge SQL string "up front" when the SessionFactory/EntityManagerFactory is being built. Again, there are real performance reasons we do it this way; but here people are specifically asking to circumvent those performance optimizations. So first, I wanted to (re)explain there optimization here.

Consider a simple domain model of a Customer, Order and LineItem. And lets assume that merge cascading is enabled on Customer.orders and Order.lineItems. At start up, Hibernate will create and cache a SQL SELECT statement for loading a Customer on merge in the detached case; that SQL SELECT will "join fetch" Customer.orders and Order.lineItems because of the merge cascading. The performance gain here is 2-fold, though mostly related to avoiding the sending of multiple commands to the database.

However, lets consider if we really honored the idea of not loading uninitialized associations on merge. So first and foremost, this would not allow us to use the pre-cached SQL SELECT because now we are performing a more contextual execution plan. So when we receive the merge(customer) call, we now have to actually walk its association tree to determine:

  1. whether it is ok to use the pre-cached SQL SELECT based on the initialized/uninitialized state of the merge graph. So here we need to check customer.getOrders(), and assuming that is initialized, for each order we need to check order.getLineItems().
  2. in the case of any of those check finding non-initialized state we cannot use the pre-cached SQL SELECT; so we have to do "something else" which could be either:
    1. build a modified "join fetch" SQL on the fly
    2. don't try to "join fetch" at all and just use n+1 selects to load the merge graph

And even in the case of walking the association tree and determining that it is in fact ok to use the pre-cached SQL SELECT, we have still incurred the overhead of walking the tree to decide that. I almost think that, for the users wanting this, there is actually not any benefit to having the load-for-merge SQL include join fetches at all. To the point where, maybe there is just a SessionFactory-wide switch that says whether to build join fetches into the pre-cached load-for-merge SQL statements.

My concern with an approach like @SkipJoinLoadOn is that at the end of the day we still have a non-contextual strategy. The to-be-cached SQL SELECT would just never include the annotated association. Another similar option would be to have a more contextual targetted annotation (maybe @SkipJoinLoadIfUninitialized).

This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira