Statistics are nice, but may also increase database load. Counting web users (page impressions) may produce a lot of UPDATE requests setting counter=counter+1. I tried to merge them using Gearman.

Gearman is able to handle a huge amount of jobs using little resources. It has no replication and usually runs in memory but even a SQLite backup file requires much less disk I/O than a database updating rows and maybe indices.

The Gearman::Worker module (which is used by worker tasks) calls a "stop_if" callback after each single processed job and every 10 to 15 seconds if no job was received (but not during job execution). stop_if is currently undocumented but stable.

$worker->work( stop_if => sub { return 0; });

Any true return value from stop_if will break the Gearman::Worker main loop between two jobs, all others break while a job is currently being processed.

Putting everything together

A simple worker would add all statistic input and flush it into the database as one, aggregated query.

# Flush the counted number of items into the database$dbh->do('INSERT INTO statistics(datetime,amount) VALUES(NOW(),?)',$count);

Every call of the AggregateJob job triggers a call of the registered anonymous sub which increases the number of items stored in $count. At some point (here: once $count reaches 100), the main loop is finished (by a true return value from the stop_if callback) and $count is inserted into the database.