Change one line to improve the performance of your Grails app drastically

Shashank Agrawal
WizPanda
Published in
6 min readApr 19, 2020
Image by mcmurryjulie from Pixabay

Do you use unique constraint in your Grails domain classes?

I’m pretty sure if your app is a mid-size app or even a starter app which is deployed on production, you must be using at least a single unique constraint in any of your domain class.

Let’s take a small example which is very common to have i.e. a User domain which holds the details (like mobile, email & password) of a user who can log-in to your app.

A Grails domain class example with unique constraint on two fields.

It is a very common use case, right? That the user table should not have two or more records with the same email & mobile.

When you run the app and see it in the database (I’m taking example with MySQL), you’ll see that a unique constraint is applied at the database level for email & mobile column.

Now, let’s insert a record in the database by running http://localhost:8080/application/save:

An example using Grails controller to insert a record in the user table.

When we run the code, a new entry will be recorded in the database.

Now, let’ again run the same code (refresh that page). What will you see?

Of course, no duplicate record will be inserted because we have added the unique constraint hence you will see the validation error in the logs.

Now let’s see the logs in the console (I have enabled detailed Hibernate query logging in my Grails application using one of our core plugin- kernel):

Outputs of two execution of the same code are separated by the green line.

Woh! What are those 3 extra database queries apart from the insert query?

That is the downside of the magic being done by Grails (GORM).

Basically, whenever you save a domain instance having any unique constraint, Grails do a silent & separate call to the database to ensure if the database has any record with the same value. And if a record with the same value exists, it does not perform the save operation and populates the validation error like being shown in the above logs.

So in our example, when we executed the code 2 times, it first checked (using two separate database calls) if an email with shashank@example.com & mobile with 9876543210 already exists or not.

That means, every database insert operation performs N number of extra queries if there are N number of unique constraints in a Grails domain class.

What will happen when we update a domain class?

If you have updated values of email or mobile fields and trying to save, then Grails will again do database calls (before the update query) to validates if there is already a record with updated email or mobile, which is obvious because you have updated the values.

But if you haven’t updated those field values, then there won’t be separate calls to validate the unique constraint.

Let’s consider another use case which developers used to take for more control.

Modified Grails controller code to add an explicit check of the uniqueness of the email & mobile.

Here, I added a separate call to check the existence of user which will make one call to check the unique values.

So technically, we have already validated if the user already exists or not (hence 1 database call already done). Now, Grails will again make 2 database calls before inserting the record in the database. That means,

Total of 2 extra database calls before inserting a record.

Out of those 3, two database calls (done by Grails) is useless because you are absolutely sure that the user with the same record doesn’t exist. Now consider, your app receives 1000 user signup weekly,

That means extra 2000 database queries are being done in your application 😲

Every single database call costs towards your monthly bill because it adds a round trip from the application server to the database server. That means 2000 extra database calls can result in a fat monthly bill from your cloud provider.

What is the solution to save the database calls?

Well, this isn’t a problem to solve. This is a powerful feature given my Grails but as a Grails developer, you MUST be aware of this extra database calls because power comes with responsibility & carefulness.

Now, let’s see the workaround which will save these extra 2 database calls.

Well, the workaround is simple:

Use uniquemapping instead of constraints

What? Is it that simple? 😮😲

Yes, you read it right in the title — Change one line to improve the performance of your app drastically.

When you define the unique mapping property, the unique constrain will still be applied at the database level but Grails won’t make extra database queries to confirm the unique values. Let’s see it in working:

Updated domain class to use the mapping instead of constraints

(Verify in your DB that unique constraint is still being applied at the database level).

Now let’s execute our code and see the output:

The output of Grails logs when unique mapping is used instead of constraints

Surprised!! Hmmm 😃

Yes, that saved those 2 database calls (hence 2000 calls for our example). Cheers! 🎉🎊

Please note, you don’t have to do any database migration as you are only changing the constraint at ORM level.

There is a point that you need to take care of when using mapping instead of constraints

Basically, when you do not use constraints that means Grails is not going to be the guard against the unique constraint and if you do not explicitly check for it, MySQL is going throw an exception when Grails will attempt to insert the record and there is a delicacy.

The exception is pretty famous — MySQLIntegrityConstraintViolationException

An example of MySQL exception when you attempt to insert a duplicate record

So consider these points when you have to choose betweenconstraints or mapping :

When to use constraints :

  1. When you know that there will be very few insert operations in a domain class having unique constraints.
  2. When you have not added any manual/explicit check (or query) to make sure that there are no duplicate records.

When to use mapping :

  1. When you have added any manual/explicit check to make sure there are no duplicate records.
  2. When you are absolutely sure that the insert operation is going to be unique only (for example, a column which is having unique values from UUID class).
  3. When the number of unique constraints is more than 1 which can be taken care of by explicit calls (like in our example).

Want to see your amazing idea in action? Or want to join us? Connect us at https://www.wizpanda.com/

(Do you use Grails database migration plugin? Check out this article as well https://medium.com/wizpanda/custom-groovy-changes-using-grails-db-migration-plugin-part-i-c51d4ee96a6e)

--

--

Shashank Agrawal
WizPanda

Serial Entrepreneur | Founder / CTO @ Cooee® — AI-driven Personalised Notifications platform for Better Customer Engagement. bit.ly/shashanka