I'm fetching a long list of entities which refer to others which refer to... and, at the end, usually of all them refer to a single user
as their owner
. Not really surprising as what's queried are entities belonging to a single user
. There are more parts duplicated in many rows; actually, just a small percentage are unique data. As the query seems to be slow, I though I could gain a bit by fetching things separately using
criteria.setFetchMode(path, FetchMode.SELECT);
This works in my above case, but when querying over many users (as admin), it gets terrible, as hibernate issues a separate query for every user
, instead of something like
SELECT * FROM User WHERE id IN (?, ?, ..., ?)
or not fetching them at all (which can't get any worse than one query per entity). I wonder what am I missing?
So instead of fetching a lot of redundant data, I ran into the 1+N problem, where obviously 1+1 queries would do.
- Is there a way to instruct Hibernate to use the right query?
- Is there a way to prevent Hibernate from fetching the owners by specifying it in the criteria itself (rather than putting
fetch=FetchType.LAZY
on the field; the laziness should be query-specific)?
I don't think it matters, but my classes are like
class Child {
@ManyToOne Father father;
@ManyToOne Mother mother;
...
}
class Father {
@ManyToOne User owner;
...
}
class Mother {
@ManyToOne User owner;
...
}
and the query is like
createCriteria(Child.class)
.add(Restrictions.in("id", idList))
.add(Restrictions.eq("isDeleted", false))
.createAlias("Father", "f")
.add(Restrictions.eq("f.isDeleted", false))
.setFetchMode("f.owner", FetchMode.SELECT)
.createAlias("Mother", "m")
.add(Restrictions.eq("m.isDeleted", false))
.setFetchMode("m.owner", FetchMode.SELECT)
.list();
The important part is that owner
does not get used and can be proxied. The javadoc for FetchMode.SELECT
says
Fetch eagerly, using a separate select
so it basically promises 1+1 querying which I want rather than "using a separate select per entity".