I wrote a benchmark to compare 3 caching methods (Cache::FileCache, Cache::MemoryCache, and a simple memory cache from here to cache response from a select using a primary key from a MySQL database.

I was a little surprised to find no speed improvement with Cache::FileCache and Cache::MemoryCache, and was also surprised at how well Randall's hash worked.

Do these results seem realistic, and does the benchmark below look correct?

Results:
 FileCache: 21 wallclock secs (18.24 usr +  1.79 sys = 20.03 CPU) @ 499.25/s (n=10000)
MemoryCache:  9 wallclock secs ( 8.97 usr +  0.02 sys =  8.99 CPU) @ 1112.35/s (n=10000)
SimpleCache:  0 wallclock secs ( 0.41 usr +  0.01 sys =  0.42 CPU) @ 23809.52/s (n=10000)
       raw: 11 wallclock secs ( 6.14 usr +  0.64 sys =  6.78 CPU) @ 1474.93/s (n=10000)
               Rate   FileCache MemoryCache         raw SimpleCache
FileCache     499/s          --        -55%        -66%        -98%
MemoryCache  1112/s        123%          --        -25%        -95%
raw          1475/s        195%         33%          --        -94%
SimpleCache 23810/s       4669%       2040%       1514%          --

Here is the code:
use strict; use warnings; my $DB = "test"; my $USER = "dbusername"; my $PASS = "dbpassword"; my $DEBUG = 0; my $BENCHMARK_LOOP_LIMIT = 10_000; my $EXPIRATION_TIME = 60; use Data::Dumper; use DBI; my $dbh = DBI->connect("dbi:mysql:$DB", $USER, $PASS, {RaiseError => 1 +}) || die "Cannot connect to db"; ### Prepare caches use Cache::FileCache; my $fc = Cache::FileCache->new({default_expires_in => $EXPIRATION_TIME +}); $fc->Clear; use Cache::MemoryCache; my $mc = Cache::MemoryCache->new({default_expires_in => $EXPIRATION_TI +ME}); $mc->Clear; # Superfluous my %cache; my $flush_interval = 10; my $flush_time = time + $flush_interval; use Benchmark qw( timethese cmpthese ); my $results = timethese ($BENCHMARK_LOOP_LIMIT, { raw => sub {my $r = raw_load_from_cachetest(5000 + int(ran +d(30)));}, FileCache => sub {my $r = fc_load_from_cachetest(5000 + int(rand +(30)));}, MemoryCache => sub {my $r = mc_load_from_cachetest(5000 + int(rand +(30)));}, SimpleCache => sub {my $r = sc_load_from_cachetest(5000 + int(rand +(30)));}, }, ); cmpthese($results); # Load straight from database sub raw_load_from_cachetest { my ($id) = @_; my $sql = qq[select * from cachetest where id=?]; my $sth = $dbh->prepare($sql); $sth->execute($id); my $result = $sth->fetchrow_hashref || return; return $result; } # Cached load using Cache::FileCache sub fc_load_from_cachetest { my ($id) = @_; my $result; my $key = "cachetest$id"; $result = $fc->get($key) || do { $result = raw_load_from_cachetest($id); $fc->set($key, $result); $result }; return $result; } # Cached load using Cache::MemoryCache sub mc_load_from_cachetest { my ($id) = @_; my $result; my $key = "cachetest$id"; $result = $mc->get($key) || do { $result = raw_load_from_cachetest($id); $mc->set($key, $result); $result }; return $result; }; # Cached load using simple cache found at: sub sc_load_from_cachetest { my ($id) = @_; ($flush_time, %cache) = time + $flush_interval if $flush_time < time +; $cache{$id} ||= raw_load_from_cachetest($id); }
The database table structure looks like this:
create table cachetest (
  id int default '0' not null auto_increment,
  a int default '0' not null,
  b int default '0' not null,
  c int default '0' not null,
  d int default '0' not null,
  e int default '0' not null,
  f int default '0' not null,
  g int default '0' not null,
  primary key(id)
);
and I pre-filled the table with 20,000 rows of pseudo-random data using
use strict; use warnings; ### Begin configuration my $DSN = "dbi:mysql:test"; my $USER = "dbusername"; my $PASS = "dbpassword"; ### End configuration use DBI; my $dbh = DBI->connect($DSN, $USER, $PASS, {RaiseError => 1}) || die "Cannot connect to db"; $dbh->do(qq[delete from cachetest]); for(my $i=1;$i<=20000; $i++) { $dbh->do(qq[insert into cachetest (a,b,c,d,e,f,g) values (?,?,?,?,?, +?,?)], undef, rand(1_000_000), rand(1_000_000), rand(1_000_000), rand(1_000_000), rand(1_000_000), rand(1_000_000), rand(1_000_000), );

Edited: ~Tue Jul 23 21:28:45 2002 (GMT), by footpad: Added <READMORE> tag. Per Consideration.


In reply to SQL Result Cache Performance Comparison by mp

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.