Change one line to improve the performance of your Grails app drastically
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.
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
:
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):
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.
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 unique
mapping
instead ofconstraints
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:
(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:
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
So consider these points when you have to choose betweenconstraints
or mapping
:
When to use constraints
:
- When you know that there will be very few insert operations in a domain class having unique constraints.
- When you have not added any manual/explicit check (or query) to make sure that there are no duplicate records.
When to use mapping
:
- When you have added any manual/explicit check to make sure there are no duplicate records.
- 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). - 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)