12

The @BatchSize annotation of hibernate allows for batched fetching of lazy-loaded entities. E.g. if i got something like:

public class Product {


    @OneToMany(fetchType=LAZY)
    @BatchSize(size=10)
    private ProductCategory category;

}

Now if I get the category of a product, Hibernate will fetch the categories of up to ten more products which are in the current session and have not yet had their category field initialized. This saves a ton of SQL calls to the database. So far so good. Now I wonder why would I not use the @BatchSize annotation on EVERY lazy loaded relationship? After all why would I want extra calls to the database? There clearly must be a reason for this, otherwise the Hibernate guys could have made it the default, but I currently can't see it.

Jan Thomä
  • 13,296
  • 6
  • 55
  • 83
  • just a small correction. "There are two ways you can configure batch fetching: on the class level and the collection level" [(docs)](http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/performance.html#performance-fetching-batch). So you should place `@BatchSize` on `ProductCategory` class, not on `Product.category` field. – Raman Chodźka Jul 10 '13 at 10:50

2 Answers2

20

I am not going to answer to your question directly but I am going to answer a more generic question which could be "I have found something that works quicker for me, Why not apply it everywhere ?"

The short answer is : You should not do preemptive optimization.

hibernate is a wonderful ORM that allows all kind of optimization. You should measure all the processes that causes an issue (the classic N+1 even if it is fast, any slow processes, etc.) and optimize to solve it.

You might gain a lot better performance by eager loading some properties because you always use them, you might need a BatchSize of 100 for some other because you know it's about the number of relations you have for that property.

Ultimately, you should not care about optimization unless you need to care about it. And you need to care when you have done measurements and found issues.

Community
  • 1
  • 1
Skyp
  • 1,185
  • 11
  • 20
  • I believe there are two important scenarios when dealing with `*ToMany` aggregation relations. First scenario is that we don't need the `*ToMany` relation at all. in this case (Lazy Loading + BatchSize) approach will help us not to load the `*ToMany` relation, so it is good. In the second scenario, we usually want to iterate over all of the aggregated entities, not some of them, so eventually, we need all of them to be fetched, and in this case, (Lazy Loading + BatchSize) approach will succeed too. what's wrong whit it? – Hossein Nasr May 24 '18 at 09:18
  • @HosseinNasr in the second scenario You will want to use ``FetchType.EAGER`` :) – thorinkor Aug 03 '18 at 08:00
  • if we use `FetchType.EAGER`, hibernate **always** fetch `*ToMany` relations regardless of our use case, but maybe we don't need them in some scenarios. if we use (Lazy Loading + BatchSize) we postpone loading them until we need them. we cost a small number of queries but we gain flexibility. – Hossein Nasr Aug 04 '18 at 07:01
10

why would I not use the @BatchSize annotation on EVERY lazy loaded relationship?

Because it is an optimization you might not need in every single case. Batch fetching like this is useful when your application is going to access product.category for many different products, so you can have a single select from category... query executed rather than N of them.

However, what if when your application accesses product.category for one Product instance, it is unlikely to access the category field of other Product instances in the same session? If you have @BatchSize enabled for that association, then you have just loaded a number of other Category instances into the session for no gain - they will never be used.

matt b
  • 138,234
  • 66
  • 282
  • 345