I'm building a web based directory for a niche industry. I would like to provide a views counter on each listing/profile, similar to how MySpace use to do it in the good old days (come back 90's MySpace, all is forgiven).
I'm using MySQL, and wondering what is the best way to record the data.
Another thread (What is the best way to count page views in PHP/MySQL?) provided the following solution by @dorkitude:
$sample_rate = 100;
if(mt_rand(1,$sample_rate) == 1) {
$query = mysql_query(" UPDATE posts SET views = views + {$sample_rate} WHERE id = '{$id}' ");
// execute query, etc
}
This works on the theory of probability, and was explained by @Suyash as
The general idea behind this is that, in theory, it should take 100 tries to hit the number '1' - and so the view count is more or less correct without the constant need to query the database.
The thread is dated 2011, and I was wondering if any better solutions had come to light since then.
Firstly, ensure tracking is done asynchronously. Do not perform tracking during page rendering. Call the tracking script using javascript after the page has loaded.
Using a sample rate will certainly help performance but will reduce accuracy for lower volumes, especially a sample rate of 1 in 100. Perhaps you could reduce the sample rate at low counts. e.g. For the first 1000 page views track every single view (disable sampling). After that use a sample rate of 100. Do NOT do this by looking up the counts in mysql. You need to pass through the pageviews counts (or equivalent sample rate) when calling the asynchronous tracking script.
If you have a huge number of records in the posts table, the WHERE lookup will add overhead. Consider inserting a tracking record in another dedicated tracking table. Then you can periodically (nightly) update posts.views by summing all the tracking records.
You could also consider an approach which periodically processes and aggregates your web server logs. This could be particularly efficient since you are probably logging all page views anyway.
The code below is similar to the one you refer to but instead of relying on probabilities to update the database it stores the count in a file and updates the db whenever the file counter reaches a certain number.
It's slower than the method you referred to but it's faster than updating a counter stored in the db for every page view especially in setups with multiple web servers and a single db.
$update_rate = 100;
$file = "/my_counters/page_view_counter_$id";
if(!file_exists($file)) {
file_put_contents($file,0);
}
$fp = fopen($file,"r+");
//acquire lock on counter file
//increment counter by 1
//if counter is equal to update rate, update count in db
//and reset counter to 0
if(flock($fp, LOCK_EX)) {
$count = fread($fp, filesize($file));
if(++$count >= $update_count) {
$count = 0;
}
rewind($fp);
fwrite($fp,$count);
flock($fp,LOCK_UN); //release lock on counter file
}
if($count == 0) {
$query = mysql_query(" UPDATE posts SET views = views + {$update_rate} WHERE id = '{$id}' ");
// execute query, etc
}