Every visit to my website updates a user’s individual hit counter and updates a column for time() based on their ip address and id stored in a cookie. So when coming to output the data, what’s a more efficient way of my following code with less database calls, as it’s essentially a copy of itself:
<?
$last1Min = time()-60;
$last5Mins = time()-300;
$last1Hr = time()-6000;
$last1Dy = time()-144000;
$last1Wk = time()-1008000;
$last1Mnth = time()-30240000;
//last1Min
$sql = "SELECT COUNT(*) FROM usersonline WHERE lastOnline > $last1Min";
while($rows = mysql_fetch_array(mysql_query($sql))) {
echo "Users online in the last minute: " . $rows['COUNT(*)'] . "<br />\n";
}
//last5Mins
$sql = "SELECT COUNT(*) FROM usersonline WHERE lastOnline > $last5Mins";
while($rows = mysql_fetch_array(mysql_query($sql))) {
echo "Users online in the last 5 minutes: " . $rows['COUNT(*)'] . "<br />\n";
}
//last1Hr
$sql = "SELECT COUNT(*) FROM usersonline WHERE lastOnline > $last1Hr";
while($rows = mysql_fetch_array(mysql_query($sql))) {
echo "Users online in the last hour: " . $rows['COUNT(*)'] . "<br />\n";
}
//last1Dy
$sql = "SELECT COUNT(*) FROM usersonline WHERE lastOnline > $last1Dy";
while($rows = mysql_fetch_array(mysql_query($sql))) {
echo "Users online in the last day: " . $rows['COUNT(*)'] . "<br />\n";
}
//last1Wk
$sql = "SELECT COUNT(*) FROM usersonline WHERE lastOnline > $last1Wk";
while($rows = mysql_fetch_array(mysql_query($sql))) {
echo "Users online in the last week: " . $rows['COUNT(*)'] . "<br />\n";
}
//last1Mnth
$sql = "SELECT COUNT(*) FROM usersonline WHERE lastOnline > $last1Mnth";
while($rows = mysql_fetch_array(mysql_query($sql))) {
echo "Users online in the last month: " . $rows['COUNT(*)'] . "<br /><br />\n";
}
If there is a more efficient way of presenting this data, I’m wanting to extend it to show not only how many users for each of these metrics is online on my entire site, but record and output the data for every page on my site.
Using this method, you can get everything you need in a single query with a single table scan; it doesn’t get much more efficient than that. As others have mentioned, you should cache the result, as it’s relatively expensive (even in this optimized form). There’s no point in calculating this on every page load, especially if you’re seeing multiple hits per second (which is extremely likely if you, say, hit the front page of digg)
lastOnline <= 60 evaluates to 1 for rows where the condition is true, and 0 for rows where the condition is false; SUM() sums these 1s and zeros, giving you a count of the number of rows for which the condition is true.
Learned this technique from a user comment in the mysql docs a few years ago; there are similar examples elsewhere