Select N+1
Select N + 1 is a data access anti-pattern where the database is accessed in a suboptimal way. Take a look at this code sample, then we'll discuss what is going on. Say you want to show the user all comments from all posts so that they can delete all of the nasty comments. The naive implementation would be something like:
// SELECT * FROM Posts List<Post> posts = session.createQuery("from Post").list()); for (Post post : posts) { //lazy loading of comments list causes: // SELECT * FROM Comments where PostId = @p0 for (Comment comment : post.getComments()) { //print comment... } }
In this example, we can see that we are loading a list of posts (the first select) and then traversing the object graph. However, we access the collection in a lazy fashion, causing Hibernate to go to the database and bring the results back one row at a time. This is incredibly inefficient, and the Hibernate Profiler will generate a warning whenever it encounters such a case.
The solution for this example is simple: Force an eager load of the collection up front. Using HQL:
List posts = session
.createQuery("from Post p left join fetch p.Comments")
.list();
Using the criteria API:
session.createCriteria(Post.class) .setFetchMode("Comments", FetchMode.JOIN) .list();
In both cases, we will get a join and only a single query to the database.
Note: this is the classical appearance of the problem. It can also surface in other scenarios, such as calling the database in a loop, or more complex object graph traversals. In those cases, it it generally much harder to see what is causing the issue.
Having said that, the profiler will detect those scenarios just as well, and give you the exact line in the source code that cause this SQL to be generated.