18

The Hibernate documentation gives some information at @BatchSize as :

@BatchSize specifies a "batch size" for fetching instances of this class by identifier. Not yet loaded instances are loaded batch-size at a time (default 1).

I am not clear on what is the purpose of this annotation, when we need to use this. Can some please help me in understanding when to use this annotation.

Chaitanya
  • 15,403
  • 35
  • 96
  • 137

3 Answers3

25

Using batch fetching, Hibernate can load several uninitialized proxies if one proxy is accessed. Batch fetching is an optimization of the lazy select fetching strategy. There are two ways you can configure batch fetching: on the class level and the collection level.

Batch fetching for classes/entities is easier to understand. Consider the following example: at runtime you have 25 Cat instances loaded in a Session, and each Cat has a reference to its owner, a Person. The Person class is mapped with a proxy, lazy="true". If you now iterate through all cats and call getOwner() on each, Hibernate will, by default, execute 25 SELECT statements to retrieve the proxied owners. You can tune this behavior by specifying a batch-size in the mapping of Person:

<class name="Person" batch-size="10">...</class>

Hibernate will now execute only three queries: the pattern is 10, 10, 5.

Aun
  • 1,883
  • 1
  • 17
  • 26
  • 1
    How does hibernate know I'm going to call getOwner on all of the cats, while only in the first iteration of the loop? Also, how does it know which I will call for? Does it just assume that, since you have 25 being monitored by the entity manager, you probably want to load them all? – Ploni Oct 17 '21 at 11:46
  • 2
    @Ploni when you first use getter of lazy relationship then hibernate looks for other objects of the same type in session. Lets say that you entered batch size of `N`. Then, for every `N` parent entities the query for fetching children is executed with use of `IN (:parentIds)` clause. If you want to use this behavior, your query must be executed in a transaction. – Michał Stochmal Nov 29 '21 at 14:23
  • @Aun : Beginner here, so please be kind. Is lazy fetching a pre-requisite to use @BatchSize? I observed that if I used the said annotation where I fetched eagerly, it still called only 3 queries (relating to the example you provided). So here also data was fetched in batches. – Drishti Jain Jul 26 '22 at 06:42
2

@BatchSize will fetch record from db based on your size. Think you have 100 records in your result and if you are defined batch size as 10 then it will fetch 10 records per db call. Logically it will increase performance.

Kanagaraj M
  • 956
  • 8
  • 18
  • Thank you for responding, if I see the statement in my post, I understand that if I am fetching a record by identifier(or ID) then it means I will get only 1 record from DB then how BatchSize helps in this case? Also what does it mean that `Not yet loaded instances are loaded batch-size at a time (default 1).`? Can you please clarify. – Chaitanya Aug 12 '14 at 18:22
  • On that time also you may have more child records. It will fetch child record based on batchsize. – Kanagaraj M Aug 13 '14 at 03:40
  • 2
    you can get the better understanding with http://stackoverflow.com/questions/6687422/hibernate-batch-size-confusion – Aun Nov 10 '14 at 11:47
  • @Aun The question you linked is for `hibernate.jdbc.batch_size`. It is totally different thing than `@BatchSize`. First is for `insert`/`update` optimization, and second is for `select` optimization. – Ruslan Stelmachenko Aug 19 '19 at 00:03
0

Let's assume that you know that for satisfying a certain request, you will have to select a specific Person from the database along with all of her Cats. As eager loading is considered code smell and mother of all evil, this association will be lazy - you still want to load the Person and all her Cat entities in one select statement.

You have several ways to do that: by using Named Entity Graphs or Dynamic Graphs, or specifying a "join fetch" in JPQL or Criteria API. Problem solved, you have an explicitly given eager loading select statement that loads everything in one step.

What if you want to query all Cats, Dogs, Mice, Lions and Parrots belonging to the Person? Assuming that all the different species are separate entities (having their own tables), you will end up with a query containing TOO MANY JOIN FETCH clauses to be effective. In this case, "eager loading" via the above way won't help.

But, with lazy loading, Hibernate will issue a select for each and every animal (creating the N+1 problem). This is the case where BatchSize can be a remedy. You can tell Hibernate to select multiple animals (of the same kind, probably) at once. For example, if you can guess how many animals (of the same kind) a Person typically has, you set that as a BatchSize for Hibernate, and you end up with one single query for each kind of animal.

If you want to see the queries (with the IN clause Hibernate uses for these batch queries), you can find a simple and short example on Thorben Janssen's site: https://thorben-janssen.com/hibernate-tips-how-to-fetch-associations-in-batches/

booFar
  • 51
  • 5