If your application runs a large number of queries very often, with time it will become very, very sluggish. Here Laravel caching comes handy. Laravel provides a simple mechanism for caching these queries using a very simple chained method call. Here is an example using Laravel’s Fluent Query Builder:

Caching Database Queries with Laravel Query Builder $users = DB::table('users') ->orderBy('latest_activity', 'desc') ->take(10) ->remember(60) ->get(); 1 2 3 4 5 $users = DB:: table ( 'users' ) -> orderBy ( 'latest_activity' , 'desc' ) -> take ( 10 ) -> remember ( 60 ) -> get ( ) ;

Of course, we can do the same thing using Eloquent:

Caching Database Queries using Eloquent $users = User::orderBy('latest_activity', 'desc') ->take(10) ->remember(60) ->get(); 1 2 3 4 $users = User:: orderBy ( 'latest_activity' , 'desc' ) -> take ( 10 ) -> remember ( 60 ) -> get ( ) ;

Behind the scene Laravel executes the query and then stores it along with the query result using the cache adapter, with an expiration time of 60 minutes. Running the same query again will result that cached query will be found, which means it will not be executed again, instead the results will be taken from the cache.

What About More Complex Queries?

If you have much more complex queries, and you use raw queries, you can cache them to, using Cache Facade:

$usersTable = Cache::remember('usersTable', 60, function() { return DB::table('users') ->select(DB::raw( "SOME COMPLEX JOINS ETC.." ))->get(); }); 1 2 3 4 5 6 7 $usersTable = Cache:: remember ( 'usersTable' , 60 , function ( ) { return DB:: table ( 'users' ) -> select ( DB:: raw ( "SOME COMPLEX JOINS ETC.." ) ) -> get ( ) ; } ) ;

Make sure to check Laravel official documentation, to see what other methods you have at disposal.

Of course, if you have such a huge application that requires caching, you will probably use this snippet in a multiple places across entire application. That’s why is better to create a generic helper method which will then handle caching:

public function cacheQuery($key, $sql, $timeout = 60) { return Cache::remember($key, $timeout, function() use ($sql) { return DB::select(DB::raw($sql)); }); } $cache = $this->cacheQuery("usersTable", "SOME COMPLEX JOINS ETC..", 30); 1 2 3 4 5 6 7 public function cacheQuery ( $key , $sql , $timeout = 60 ) { return Cache:: remember ( $key , $timeout , function ( ) use ( $sql ) { return DB:: select ( DB:: raw ( $sql ) ) ; } ) ; } $cache = $this -> cacheQuery ( "usersTable" , "SOME COMPLEX JOINS ETC.." , 30 ) ;

UPDATE: A better solution for handling cache keys is to make MD5 hash from SQL Query, as suggested in this Stackoverflow answer, therefore previous method will look something like this:

Laravel Caching Complex Queries public function cacheQuery($sql, $timeout = 60) { return Cache::remember(md5($sql), $timeout, function() use ($sql) { return DB::select(DB::raw($sql)); }); } $cache = $this->cacheQuery("SOME COMPLEX JOINS ETC..", 30); 1 2 3 4 5 6 7 public function cacheQuery ( $sql , $timeout = 60 ) { return Cache:: remember ( md5 ( $sql ) , $timeout , function ( ) use ( $sql ) { return DB:: select ( DB:: raw ( $sql ) ) ; } ) ; } $cache = $this -> cacheQuery ( "SOME COMPLEX JOINS ETC.." , 30 ) ;

UPDATE 2: Thank you all for your feedback and for making this article much better

Cache Sections

Note: Cache sections are not supported when using the file or database cache drivers.

Cache sections were first introduced in Laravel 4.0. With cache sections we got a possibility to bundle a specific dataset in the cache. Flushing all of the cached data is done simply by calling section’s name. On the official documentation page I couldn’t find any reference on how to use cache sections, but fortunately there is an Api Documentation for the Cache Section class.

Here we can see pretty standard set of methods that we can use. Caching queries in the sections can be done in following way:

Cache Section function cacheQuery($key, $timeout = 60) { return Cache::section('departments')->remember($key, $timeout, function() { return Department::all()->toArray(); }); } cacheQuery("all-departments", $timeout = 60); 1 2 3 4 5 6 7 function cacheQuery ( $key , $timeout = 60 ) { return Cache:: section ( 'departments' ) -> remember ( $key , $timeout , function ( ) { return Department:: all ( ) -> toArray ( ) ; } ) ; } cacheQuery ( "all-departments" , $timeout = 60 ) ;

After you open the page that execute this query, result of the query will be stored in the cache and you’ll get expected result.

Accessing Items In A Section Cache

To access a section cache use section name used to save it.

Cached section $cached_section = Cache::section("departments")->get('all-departments'); var_dump($cached_section); 1 2 3 $cached_section = Cache:: section ( "departments" ) -> get ( 'all-departments' ) ; var_dump ( $cached_section ) ;

I created simple route, just to demonstrate this:

Now, if we reload the same page again we see the same result, but no query was executed whatsoever. That’s because this dataset is fetched from the cache.

Now, if you make any change in these Departments, if you delete or add new ones, these changes will not be visible for another 60 minutes (that is expiration time I set in this example). This is not an good option in a real production-ready applications, because you want to flush cache whenever Model is changed.

Laravel 4.1 version has brought us a lot of new features. One of these are cache tags. Now it is possible to tag individually cached objects and flush these separately from everything else in our application cache.

Note: Same as with Cache Sections, Cache Tags are not supported when using the file or database cache drivers.

As documentations states, you can store a tagged cache by passing in an ordered list of tag names as arguments, or as an ordered array of tag names:

function cacheTags($tags, $depKey, $sql, $timeout = 60) { return Cache::tags("employees", "managers")->remember($depKey, $timeout, function() use($sql) { // Some join query that will return all Managers from selected Department return DB::select(DB::raw($sql)); }); } 1 2 3 4 5 6 function cacheTags ( $tags , $depKey , $sql , $timeout = 60 ) { return Cache:: tags ( "employees" , "managers" ) -> remember ( $depKey , $timeout , function ( ) use ( $sql ) { // Some join query that will return all Managers from selected Department return DB:: select ( DB:: raw ( $sql ) ) ; } ) ; }

Now you can use this helper method as follows:

$sql = "SOME COMPLEX LEFT JOIN.."; cacheTags(["employees", "managers"], "departments_support", $sql); $sql = "ANOTHER COMPLEX LEFT JOIN.."; cacheTags(["employees", "developers"], "departments_support", $sql); $sql = "..."; cacheTags(["employees", "managers"], "departments_it", $sql); $sql = "..."; cacheTags(["employees", "developers"], "departments_it", $sql); 1 2 3 4 5 6 7 8 9 10 11 $ sql = "SOME COMPLEX LEFT JOIN.." ; cacheTags ( [ "employees" , "managers" ] , "departments_support" , $ sql ) ; $ sql = "ANOTHER COMPLEX LEFT JOIN.." ; cacheTags ( [ "employees" , "developers" ] , "departments_support" , $ sql ) ; $ sql = "..." ; cacheTags ( [ "employees" , "managers" ] , "departments_it" , $ sql ) ; $ sql = "..." ; cacheTags ( [ "employees" , "developers" ] , "departments_it" , $ sql ) ;

Accessing Items In A Tagged Cache

Similar as we did to access a Section Cache, to access items in a tagged cache we pass the tag or the same ordered list of tags used to save it:

$d = Cache::tags(["employees", "managers"])->get('departments_it'); var_dump($d); 1 2 3 $d = Cache:: tags ( [ "employees" , "managers" ] ) -> get ( 'departments_it' ) ; var_dump ( $d ) ;

Voilà! Here is the result:

I hope that you have learned something new and that now you have a basic idea how to use this concept of caching in your Laravel application. Stay tuned for the next article where I’ll explain how to use Model observer to invoke Cache::flush() when Model is changed.

If you have any questions or suggestions feel free to drop a comment in a section bellow.

Share this: Facebook

Google

Twitter

Reddit

Pocket

Email

Print



Like this: Like Loading...