Updated 5 February 2020
In this article, we’re going to look at how to use objecting caching to further improve the performance of slow queries or computationally expensive parts of our Laravel application.
The idea behind object caching, as opposed to browser caching or page caching, is that you store the results of a slow database query or a computationally expensive bit of code in the cache for a short period of time.
This means that subsequent attempts to retrieve the same data can be served quickly from the cache rather than having to fetch the data from scratch all over again.
Laravel Cache API supports several different “drivers” for storing cache data (including file, database, memcached and Redis) and they all act as a simple key-value store.
For the purposes of this article, we’re going to be using Redis as our cache as it stores cache data in RAM making it very fast to access.
Let’s imagine that we want to build some kind of report for our tasks table. If we wanted to show a graph of how many tasks were created per day our query would look something like this:
1 2 3 4 5 6 |
$results = DB::table('tasks') ->select(DB::raw('COUNT(*) as total, DATE(created_at) as date')) ->where('user_id', $user->id) ->groupBy('date') ->orderBy('date', 'asc') ->get(); |
Now let’s say we do some kind of processing to these results before we display them in our report. For the purposes of demonstration we can simulate this by making the php sleep for a short time for each result:
1 2 3 4 5 |
foreach ($results as $item) { // Simulate expensive processing //here your codes usleep(5000); } |
To give you an idea of performance, on my machine with the user having ~850,000 tasks loading the page with this code takes ~10 secs (the database query taking ~350 ms).
If this report was being used by lots of people every day the slow load time would quickly make it annoying to work with. Let’s see how we can resolve this with some object caching.
Implementing object caching in Laravel is actually very simple. First I’m going to assume you have Redis up and running on the default port (6379
). Next, make sure you are using the Redis cache driver in your .env
file:
1 |
CACHE_DRIVER=redis |
1 2 |
<span class="hljs-attribute">composer</span> require predis/predis |
Now that Redis caching is set up in our Laravel application, let’s modify our code to actually implement some object caching.
Instead of manually checking to see if the cache has the data we need and then returning it if it does, we’ll use Laravel’s handy remember methods to retrieve and store the data in one call:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$cacheKey = 'tasks.' . $user->id; $results = Cache::remember($cacheKey, now()->addHours(24), function() use ($user) { $results = DB::table('tasks') ->select(DB::raw('COUNT(*) as total, DATE(created_at) as date')) ->where('user_id', $user->id) ->groupBy('date') ->orderBy('date', 'asc') ->get(); foreach ($results as $item) { // Simulate expensive processing usleep(5000); } return $results; }); |
There are a few things to note from the code above. First, the key we used to store the cache data has $user->id
in it to make it unique to this user.
You need to be careful that when you use the object cache the data isn’t going to be leaked to other users or that the wrong data is shown because a variable in the code has changed but is not included in the cache key.
For example, say you wanted to filter the tasks by the created_at
date. If you added another WHERE
clause to the query to filter by date it will change the results of the query. So you would need to make sure to add the variable used in the filter to the cache key.
Hope it will be helpful for you. If you have any issue feel free to raise a ticket at https://bagisto.uvdesk.com/en/
If you have more details or questions, you can reply to the received confirmation email.
Back to Home
Be the first to comment.