Search code examples
hibernategrailsgrails-ormquery-performancegrails-2.3

Optimisation: Eager fetching of base domain class instances


A Grails application maintains data about saved documents.

Simple hierarchy of domain classes is created for that with base domain class called Document.

Currently table-per-subclass approach is used. It not the most efficient but it is OK for now.

Access to documents is controlled with ACL which is modelled with another domain class.

In one particular situation a bunch of documents assigned to one ACLs to has to be assigned to another regardless of the instance type (on the top level).

ACL has eager fetching of documents with batches declared to optimise reading documents.

class Document {
}

class Image extends Document {
}

class ACL {
  Collection documents
  static mapping = {
     documents   lazy: false, batchSize: 100
  }

}

Enabling eager fetching did not improve performance a lot.

SQL logging was enabled to analyse the problem. I found out that records for Document were fetched as expected, however for each of the documents additional join query with tables for subclasses was executed for each of the elements in documents collection when iterating with for loop.

ACL original = ACL.get(id)
for (doc in original.documents) {
  // Do whatever needs to be done
}

I assumed that this behaviour is triggered because explicit type was not used for doc. I tried this:

ACL original = ACL.get(id)
for (Document doc : original.documents) {
  // Do whatever needs to be done
}

Unfortunately it did not help.

Is there a way to tell Grails that it shall not fetch data from tables for subclasses because it is not necessary: just base class will be used?


Solution

  • No, there isn't a way to tell Hibernate (which is actually doing this, not Grails) to do that. If you need this type of optimization you will need to use raw SQL, not HQL, or GORM based queries.

    To explain why this isn't possible you need to consider this from an ORM perspective. In your domain example you have presented here "Documents" aren't being saved, "Images" are. The concrete instance is always that of "Image" and never "Document". In order to hydrate a list of documents the ORM must load not only the data from the base class but the implementing class as well. This can't be avoided. Avoiding this would create an instance of a class that isn't a valid representation of the domain.

    This is one of the prices you must pay for using an ORM.