Reputation: 249
I have an application in production use, when a user goes to a proposal index page it takes a very long time and sometimes times out. I've narrowed down the issue to be a SQL statement that is selecting all the Proposal objects. The problem is the Proposal object has many images (byte[]) stored in memory that aren't being used in the index page. These images are huge thus causing the problem.
What are the different ways I can optimize this query in Grails to remove the attributes I don't need on that page or only add the attributes I have in my GSP?
Here is the controller code (scaffolded):
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond Proposal.list(params), model:[proposalInstanceCount: Proposal.count()]
}
Thanks!
Upvotes: 2
Views: 320
Reputation: 75681
I wrote a plugin for this scenario, see http://grails.org/plugin/lazylob
Another option is to refactor the domain class into two. Put the image data in the new domain class:
class ProposalImage {
byte[] image
}
and reference it from the Proposal class:
class Proposal {
ProposalImage proposalImage
// other properties
}
Since references are lazy by default, GORM will only load the image data from the new domain class if you specifically refer to it.
EDIT (updated with subselect approaches):
You can also use custom queries to select a subset of the properties. Probably the most convenient would be using "select new map" in an HQL query:
def results = Proposal.executeQuery(
'select new map(prop1 as prop1, prop2 as prop2) from Proposal',
[max:params.max as int, params.offset as int])
This is convenient because each element in the results list is a map keyed with the property names, so it will look the same as a real Proposal instance in the GSP.
Another option if you prefer criteria queries is to use projections to limit which properties are returned:
def results = Proposal.withCriteria {
projections {
property 'prop1'
property 'prop2'
}
maxResults(params.max as int)
firstResult(params.offset as int)
}
Each item in the results is an Object[] array and each element in the array is the actual type of the property. You would need to manually build a list of maps, e.g.
results = results.collect { result -> [prop1: result[0], prop2: result[1]] }
Additionally, you can automate this by finding all of the names of the persistent properties and excluding the one (or ones) you want to avoid: def propNames = grailsApplication.getDomainClass(Proposal.name).persistentProperties*.name
Upvotes: 5