Strict Standards: gmmktime(): You should be using the time() function instead in /home/richard3/public_html/index.php on line 20

Strict Standards: mktime(): You should be using the time() function instead in /home/richard3/public_html/index.php on line 20

Warning: Cannot modify header information - headers already sent by (output started at /home/richard3/public_html/index.php:20) in /home/richard3/public_html/index.php on line 25
Innvo.com: Loading MyISAM Tables Into Memory

Loading MyISAM Tables Into Memory

Page last updated on 2011 / 16 / 08

Adding indexes to MyISAM tables usually help (and sometimes hinder) performance allowing MySQL to sift through smaller amounts of data. Regardless of whether indexes have been made, data typically still has to be read from storage (typically a hard disk drive). Disks are the main bottleneck in database applications today, though faster solid state drives are combating this issue.

For regularly accessed indexes, you may want to consider the LOAD INDEX INTO CACHE statement MySQL Manual, that will load indexes of a particular table from disk to memory. Although the manual states that you can choose particular indexes of a table, the current behaviour is for MySQL to load all indexes of a table into memory.

This strategy makes use of the key buffer (MySQL Manual) which stores the most frequently accessed index keys into memory. LOAD INDEX INTO CACHE effectively loads all keys into memory so lookups are fast from the start. To ensure that the command to load indexes into memory works, you should ensure that the key buffer variable in your my.cnf file is large enough to fit the index into memory.

For an example of this in action, check out the storing MD5 values article which puts the index into memory, an adaptation of it is below so you can try it for yourself.

For this benchmark, creating the table `md5values16` is suffice for testing

  1. CREATE TABLE IF NOT EXISTS `md5values16`
  2. (
  3. `hash` BINARY(16) NOT NULL,
  4. UNIQUE KEY `hash` (`hash`)
  5. )
  6. ENGINE=myisam;
  7.  

The following script will populate the table with 1,000,000 values. It should only take a few seconds to process.

  1. <?php
  2. // Filling the table with 100,000 values
  3. mysql_connect('localhost','root','root');
  4. mysql_select_db('test');
  5. for($i = 1;$i < 1000000;$i+= 10000)
  6. {
  7. echo $i,' ';
  8. $array = array();
  9. for($j = $i;$j < $i + 10000;$j++)
  10. {
  11. $array[] = '(UNHEX(MD5(\''.$j.'\')))';
  12. }
  13. mysql_query('INSERT INTO md5values16 VALUES '.implode(',',$array)) or die(mysql_error());
  14. }
  15. ?>
  16.  

Now, the benchmark script. Note that with MyISAM tables, your Operating System will also play a role in caching data, which can sometimes lead to unusual or unpredicted results. The data I created above was added straight after restarting the MySQL server to ensure the data had not been 'touched' yet.

  1. <?php
  2.  
  3. // Benchmark tables
  4. mysql_connect('localhost','root','root');
  5. mysql_select_db('test');
  6.  
  7. function microtime_float()
  8. {
  9. list($usec, $sec) = explode(" ", microtime());
  10. return ((float)$usec + (float)$sec);
  11. }
  12.  
  13. function perform_benchmark()
  14. {
  15. for($pass = 1;$pass <= 5;$pass++)
  16. {
  17. $time_start = microtime_float();
  18. for($i = 0;$i < 50000;$i++)
  19. {
  20. $rand = rand(1,100000);
  21. mysql_query('SELECT SQL_NO_CACHE hash FROM md5values16 WHERE hash = UNHEX(MD5(\''.$rand.'\'))');
  22. }
  23. echo "Pass $pass took\t".(microtime_float() - $time_start)." seconds\n";
  24. }
  25. }
  26.  
  27.  
  28. mysql_query('SET @@global.key_buffer_size = 32768;') or die(mysql_error());
  29. echo "Performing 5 passes with tiny key buffer\n";
  30. perform_benchmark();
  31. mysql_query('SET @@global.key_buffer_size = 8388608;') or die(mysql_error());
  32. echo "Performing 5 passes with 8MB key buffer\n";
  33. perform_benchmark();
  34. mysql_query('SET @@global.key_buffer_size = 0;') or die(mysql_error());
  35. mysql_query('SET @@global.key_buffer_size = 67108864;') or die(mysql_error());
  36. mysql_query('LOAD INDEX INTO CACHE md5values16;') or die(mysql_error());
  37. echo "Performing 5 passes with whole index in key buffer (64MB)\n";
  38. perform_benchmark();
  39.  
  40. ?>
  41.  

The results:

Performing 5 passes with tiny key buffer

  1. Pass 1 took 9.7664041519165 seconds
  2. Pass 2 took 9.0273330211639 seconds
  3. Pass 3 took 9.7535579204559 seconds
  4. Pass 4 took 9.2537310123444 seconds
  5. Pass 5 took 9.0727047920227 seconds

Performing 5 passes with 8MB key buffer

  1. Pass 1 took 9.414717912674 seconds
  2. Pass 2 took 8.8966379165649 seconds
  3. Pass 3 took 8.0092940330505 seconds
  4. Pass 4 took 7.690486907959 seconds
  5. Pass 5 took 7.0581459999084 seconds

Performing 5 passes with whole index in key buffer (64MB)

  1. Pass 1 took 5.8024401664734 seconds
  2. Pass 2 took 5.6130590438843 seconds
  3. Pass 3 took 5.5719788074493 seconds
  4. Pass 4 took 5.6170449256897 seconds
  5. Pass 5 took 5.328222990036 seconds

This is not perhaps the best example, as a fair percentage of the time taken in all passes is not the actual lookup of the data, e.g. the conversions of the MD5 values and sending the query. Regardless, the benefit is apparent when accessing an index in memory rather than on disk.


Previous Article
Tip: Storing MD5 Values
Next Article
Storing InnoDB Tables on Multiple Directories and Disks





Tweet