'Increasing efficiency in Grails' post illustration

Increasing efficiency in Grails

avatar

Modern web applications are counting on the big amount of users, so efficiency is a very important aspect of a web development. Today we’ll talk about the ways to increase efficiency of the web application, developed on the Grails platform.

Let’s imagine that we are developing the web service that helps to sell a used cars. And we need to write a request that will return the amount of cars that had been produced between two dates and in the specified region, i.e. amount of cars that had been produced in Asia between 1990 and 2000 year. This example is written for using mongoDB database and tested on mongodb Grails plugin, version 1.0.0.M6
Let’s first take a look on the domain objects that will be used in our example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Car {
   ObjectId id
   String brand
   String fullName
   long productionDate
   String serialNumber
   Country country
}

class Country {
   ObjectId id
   String name
   String region
}

First thing that should increase working with a database collection speed is adding some indexes. Let’s say that unique id for Car collection is a car serial number
So you should add index for this field by specifying it this way in a Car domain class:

1
2
3
static mapping = {
   serialNumber index: 'serial_number_index'
}

Now, let’s take a look on a Country class. Obviously this collection isn’t the one that will change often. So for this class it will be nice to use a cache.
Let’s use EhCache library for our example. So you should specify following code in a DataSource.groovy file:

1
2
3
4
5
hibernate {
   cache.use_second_level.cache = true
   cache.use_query_cache = true
   cache.provider.class = 'net.sf.ehcache.hibernate.EhCacheProvider'
}

To make request to the Country collection use cache, specify this in domain class:

1
2
3
static mapping = {
   cache: "read-only"
}

“read-only” value should be used only for the static data, otherwise use “read-write” value. Settings of the EhCache library are placed in the grails-app/conf/ehcache.xml file.
Here is a common example of configuring a cache for a domain class:

1
2
3
4
5
6
7
8
<cache
   name="com.sysgears.country"  //class to cache
   maxElementsInMemory="1000"
   eternal="false"
   timeToIdleSeconds="3600"
   timeToLiveSeconds="3600" // limit time of caching
   overflowToDisk="false"
/>

Now let’s proceed to writing a request.

1
2
3
4
5
6
7
8
9
10
11
12
int result = 0
List<Country> countries = Country.findAllByRegion(region)
Car.findAll().each { Car car ->
   countries.each {
       if (car.country.equals(it) &&
           (car.productionDate > startDate &&
               car.productionDate < endDate)) {
               result++
               return
       }
   }  
}

Now this is a first implementation that may come to your mind. But it may extremely slow down the work of our service. On my computer (Intel core i3-2100 processor, 8GB RAM) processing this request took about 12 ms in conditions that Cars collection has 44 records and Country collection has 66 records. Notice that this solution wasting a memory on the creating and processing unnecessary objects.
The main goal of writing the requests is to perform as much as possible operations within the database. So let’s rewrite the request using the criteria.

1
2
3
4
5
List<ObjectId> countries = Country.findAllByRegion(region).id
int result = Car.createCriteria().count {
   'in'('country', countries)
   between('productionDate', startDate, endDate)
}

Now this request is much more effective than the previous one, the time of processing speaks for itself, it takes about 1-2 ms to process the request. So building a smart requests using criteria is a great way to increase Grails application productivity.

If you're looking for a developer or considering starting a new project,
we are always ready to help!