MyLyricsFinder.com: Caching MySQL Queries

Filed Under (General) by Wenbert on 28-10-2007

Tagged Under : , , , ,

It is Saturday night and it is raining like it hasn’t rained in weeks. So I decided to spend the night to work on my pet project: MyLyricsFinder.com.

It uses the Zend Framework. The latest addition tonight is Zend_Cache. I added the Top 10 Songs and Artist list in the frontpage - so caching it would make sense. Without the cache, every user that will visit the site will have to query the database. Getting the top 10 list from 200K+ rows is pretty heavy on the resources. Not to mention the overhead it will cause on the user’s side. So I came up with the code below:

  1.  
  2. //this code snippet is part of my indexAction() in my IndexController
  3.  
  4. //for the cache
  5. $frontendOptions = array();
  6. $frontendOptions[‘lifetime’] = 3600;
  7. $frontendOptions[‘automatic_serialization’] = true;$backendOptions = array();
  8. $backendOptions[‘cache_dir’] = Zend_Registry::get(‘cache_dir’);
  9.  
  10. // getting a Zend_Cache_Core object
  11. $cache = Zend_Cache::factory(‘Core’, ‘File’, $frontendOptions, $backendOptions);
  12.  
  13. // see if a cache already exists:
  14. if(!$result_pop_songs = $cache->load(‘pop_songs’)) {
  15.     //get most popular songs
  16.     $dbAdapter = Zend_Registry::get(‘dbAdapter’);
  17.     $sql = ‘SELECT
  18.            s.song_title,
  19.            s.song_slug,
  20.            s.song_counter,
  21.            at.artist_slug
  22.            FROM songs_table s
  23.            LEFT JOIN album_table al ON s.album_id=al.album_id
  24.            LEFT JOIN artist_table at ON al.artist_id=at.artist_id
  25.            WHERE s.song_counter>0 ORDER BY s.song_counter DESC LIMIT 10′;
  26.     $this->view->pop_songs = $dbAdapter->fetchAll($sql);
  27.     $cache->save($this->view->pop_songs, ‘pop_songs’);
  28. } else {
  29.     // cache hit! shout so that we know
  30.     //echo "This one is from cache!\n\n";
  31.     $this->view->pop_songs = $result_pop_songs;
  32.  
  33. }

In addition to the Top 10 List in the frontpage, I have also cached the list of Artist per Letter and the List of Albums per Artist. I have reduced the number of database requests significantly - although I don’t know how much - I can tell the difference in load time with and without the cache.

Code Walkthough

  1.  
  2. $frontendOptions = array();
  3. $frontendOptions[‘lifetime’] = 3600;
  4. $frontendOptions[‘automatic_serialization’] = true;
  5. $backendOptions = array();
  6. $backendOptions[‘cache_dir’] = Zend_Registry::get(‘cache_dir’);
  7. $cache = Zend_Cache::factory(‘Core’, ‘File’, $frontendOptions, $backendOptions);

This part of the code sets up the Zend_Cache. Most likely, yours will be similar to this. Except for the line with the get(’cache_dir’). I have set up Zend_Registry::get(’cache_dir’) in my Bootstrap file to “../tmp/”

  1.  
  2. if(!$result_pop_songs = $cache->load(‘pop_songs’)) {

The line above checks if a cache for ‘pop_songs’ already exists. If not, then it will query the database with the code below:

  1.  
  2. $dbAdapter = Zend_Registry::get(‘dbAdapter’);
  3.     $sql = ‘SELECT
  4.            s.song_title,
  5.            s.song_slug,
  6.            s.song_counter,
  7.            at.artist_slug
  8.            FROM songs_table s
  9.            LEFT JOIN album_table al ON s.album_id=al.album_id
  10.            LEFT JOIN artist_table at ON al.artist_id=at.artist_id
  11.            WHERE s.song_counter>0 ORDER BY s.song_counter DESC LIMIT 10′;
  12.  
  13.     $this->view->pop_songs = $dbAdapter->fetchAll($sql);
  14.  
  15.     $cache->save($this->view->pop_songs, ‘pop_songs’);

The last line will save the query into the cache. So the next time a user will come, the ‘pop_songs’ cache will already exist in the cache and the code below is executed:

  1.  
  2. $this->view->pop_songs = $result_pop_songs;

Leave a Reply

Subscribe to Rss Feed : Rss