7.3.4 Eager and Lazy Fetching - Reference Documentation
Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith, Lari Hotari
Version: 3.1.1
7.3.4 Eager and Lazy Fetching
Associations in GORM are by default lazy. This is best explained by example:class Airport { String name static hasMany = [flights: Flight] }
class Flight { String number Location destination static belongsTo = [airport: Airport] }
class Location { String city String country }
def airport = Airport.findByName("Gatwick") for (flight in airport.flights) { println flight.destination.city }
Airport
instance, another to get its flights, and then 1 extra query for each iteration over the flights
association to get the current flight's destination. In other words you get N+1 queries (if you exclude the original one to get the airport).Configuring Eager Fetching
An alternative approach that avoids the N+1 queries is to use eager fetching, which can be specified as follows:class Airport { String name static hasMany = [flights: Flight] static mapping = { flights lazy: false } }
flights
association will be loaded at the same time as its Airport
instance, although a second query will be executed to fetch the collection. You can also use fetch: 'join'
instead of lazy: false
, in which case GORM will only execute a single query to get the airports and their flights. This works well for single-ended associations, but you need to be careful with one-to-manys. Queries will work as you'd expect right up to the moment you add a limit to the number of results you want. At that point, you will likely end up with fewer results than you were expecting. The reason for this is quite technical but ultimately the problem arises from GORM using a left outer join.So, the recommendation is currently to use fetch: 'join'
for single-ended associations and lazy: false
for one-to-manys.Be careful how and where you use eager loading because you could load your entire database into memory with too many eager associations. You can find more information on the mapping options in the section on the ORM DSL.Using Batch Fetching
Although eager fetching is appropriate for some cases, it is not always desirable. If you made everything eager you could quite possibly load your entire database into memory resulting in performance and memory problems. An alternative to eager fetching is to use batch fetching. You can configure Hibernate to lazily fetch results in "batches". For example:class Airport { String name static hasMany = [flights: Flight] static mapping = { flights batchSize: 10 } }
batchSize
argument, when you iterate over the flights
association, Hibernate will fetch results in batches of 10. For example if you had an Airport
that had 30 flights, if you didn't configure batch fetching you would get 1 query to fetch the Airport
and then 30
queries to fetch each flight. With batch fetching you get 1 query to fetch the Airport
and 3 queries to fetch each Flight
in batches of 10. In other words, batch fetching is an optimization of the lazy fetching strategy. Batch fetching can also be configured at the class level as follows:class Flight {
…
static mapping = {
batchSize 10
}
}