Last update, January 17, 2005
Overview
Problem
Suppose we have a class Manufacturer with a
many-to-one relationship with Contact. In other
words, one contact can be related to many manufacturers (think,
for example, of our contact as a reseller for one or
more manufacturers, but with exclusive right to sell for the
manufacturer).
Lets suppose we want to list the name of the manufacturers, but for the purposes of this query we do not care about any of the manufacturer's contact information. We simply run the query
Query query = session.createQuery( "from Manufacturer manufacturer"); List list = query.list(); //do something with the list of Manufacturer instances
The query that Hibernate generates is to get the data that we want is
select ... various field names ... from MANUFACTURER
We're okay so far. The problem is what comes next. Without us
asking it to do anything, we get another set of SQL statements,
one for each of the five referenced contacts in the
CONTACTS table.
select ... various field names ... from CONTACT where CONTACT.id=? select ... various field names ... from CONTACT where CONTACT.id=? select ... various field names ... from CONTACT where CONTACT.id=? select ... various field names ... from CONTACT where CONTACT.id=? select ... various field names ... from CONTACT where CONTACT.id=?
This is the N+1 selects problem
Solution
The solution is to make the Contact class lazy,
simply by enabling the lazy attribute in the
Contact's hbm.xml mapping definition
file.
<class name="example.domain.Contact" table="CONTACT" lazy = "true"> ... </class>
A similar effect can be achieved by using the proxy =
"example.domain.Contact" attribute.
The result is for the same code we executed earlier, only the first select statement is executed. Of course, we are still vulnerable to the N+1 selects problem if, at some point in the future, someone actually decides they need to use Contact information. We show how to deal with this pitfall in Avoiding The N+1 Selects
More Hibernate Tips and Pitfalls