This is shockingly simple… Almost so simple that I’m waiting for the problems, but after five days there has been none so far!
When you develop a web application, at some point SQL query optimization just don’t cut it anymore. At Gatorpeeps, you will see we show each user’s latest blog post underneath each of his updates. The problem with this is that on any given page, we’ll run a query per update to get the user’s latest blog post. This is less than ideal, since it is repeating the same queries for every single visitor to a Gatorpeeps page.
What we want to do is to cache the repetitive query for a certain amount of time, so that instead of querying the database, it fetches it from the cache, dramatically reducing database load and improving speed.
With the Kohana PHP framework you have a number of options to your disposal namely:
- File – File cache is fast and reliable, but requires many filesystem lookups.
- SQlite – Database cache can be used to cache items remotely, but is slower.
- Memcache – Memcache is very high performance, but prevents cache tags from being used.
- APC – Alternative Php Cache
- Eaccelerator
- Xcache
We opted for Memcached since it is fast, stable (so far at least!) and extremely simple to get going. We installed and configured it on our server (you should find lots of great guides for doing this if you search for it). We made sure the daemon is running then configured Kohana to use it. Very simple:
Open the cache.php file located in the system/config directory. Change it to:
$config['default'] = array ( 'driver' => 'memcache', 'params' => '', 'lifetime' => 3600, 'requests' => 1000 );
If you run Memcached on the same server as your PHP site, you can skip ahead and implement it. If you run it on a different server, you need to change the cache_memcache.php file also located in system/config. If you have more than one memcached server, you can add them to the $config['servers'] array.
$config['servers'] = array ( array ( 'host' => '127.0.0.1', 'port' => 11211, 'persistent' => FALSE, ) ); /** * Enable cache data compression. */ $config['compression'] = FALSE;
In your source code, you can now use the cache. We have a static function in a helper method to fetch the latest blog post of a user. We get a cache instance and we check if the entry exists in the cache. If it does, we return the result otherwise we add it to the cache with a lifetime of 10 minutes.
<?php
... truncated ...
public static function getUserLatestBlogPost($user_id)
{
$cache = Cache::instance();
// Get the latest blog post from the cache by looking for an unique id like latest_post_123
$post = $cache->get('latest_post_' . $user_id);
if ($post) {
// Found an entry in the cache. Return it.
return $post;
} else {
// There is nothing in the cache for this user, so we need to fetch it from the database and
// add it to the cache.
$newpost = self::sqlUserLatestBlogPost($user_id);
// Add it to the cache, changing the default lifetime from 1 hour (3600 seconds) to 10 minutes (600 seconds)
$cache->set('latest_post_' . $user_id, $newpost, NULL, 600);
return $newpost;
}
}
... truncated ...
That’s it. It is really that simple! :) Now, you would probably want to write a method that deletes an old entry if a new entry is inserted into the database and reload the new blog post into the cache.
REMEMBER: Use caching wisely! It is great, but as they say, too much of a good thing is bad. First make sure your SQL queries are properly optimized before you cache it. Make sure the data you cache is okay to be cached. What I mean by that is it would be senseless to cache data that is very dynamic and changes often. Caching everything WILL have an undesirable effect ;)
Welcome back! You should subscribe to my RSS feed here.
You should follow me on Twitter here
You should follow me on Gatorpeeps here.






