You may wish to use Hibern8 IDE and IronTrack SQL in conjunction to test the SQL generated by your HQL queries. Simply launch the Hibern8 IDE as described in Chapter 8, specifying hibernate.properties with the p6spy configuration, as shown in Listing 10.1.
After loading the first *.hbm.xml file, you can connect to the Hibern8 IDE instance with the IronTrack SQL monitor via TCP/IP. Assuming that you are using the default configuration values and are running your application on your local system, you will then be able to connect to the Hibern8 IDE instance and see real-time results of your HQL—both the generated SQL and the resulting timing information.
When using Hibern8 IDE and IronTrack SQL in conjunction, you may obtain better results if you disable your cache and connection pool settings.
Two areas are of special interest in regard to query performance—lazy objects and collections.
When designing your application, you should generally default to lazy="true" whenever possible, and then tune your application to ensure that your queries return the object set as needed (see the class tag in Chapter 5 for more information).
As shown in Chapter 8, it's easy to write a query that uses the fetch outer join command to have Hibernate automatically load the child objects of a collection that has been marked lazy="true". Thus the rule of thumb should be: only use lazy="false" if you expect to actually need access to the collection on every possible read.
Figure 10.7 Real-Time HQL Testing
This is likely to be an area of some confusion when you start working with Hibernate. For example, given a teacher -> student relationship, if lazy="false", loading the teacher will load the entire class. Similarly, if lazy="true" and the students aren't pre-fetched by a fetch statement (or the Criteria.setFetchMode()), iterating through the teacher's student list will generate a new SQL SELECT statement for each student.
Many of the performance issues pertaining to collections derive from the semantic collision between what most developers think of as a collection and the actual contracts of a collection. For example, duplicates are not allowed when you are inserting a value into a set, so when adding a new element, Hibernate needs to at least know the primary-key identifier(s). Similarly, for a map, the keys need to be loaded to ensure the proper ordering. The index values must be known for a list (and other indexed collections). The only collection that doesn't have any of these rules is bag, but it offers poor performance when loading data.
After reading the rules regarding collections, you may find that it would be better (or even required) to model your data with a class declared for the collection table, an example of which is shown in Chapter 4. In this case, instead of letting Hibernate to manage the collection for you behind the scenes using the collections contracts, you are free to implement your own queries and retrieval policies.
An area of special interest when working with collections is the extent to which outer joins (as described in Chapter 8) and lazy fetching are used to optimize performance. You can use the lazy="true" attribute (as described above and in Chapter 5) to reduce the amount of collection data returned and various outer joins to control the results more carefully, as described in Chapter 8.