2011-01-10, 02:45 AM
This is a big one. I'm having to go through all my queries and functions looking for some deep problem areas. I just found one. So I'm going to immediately ask that MyBB team review this and discuss if what I'm saying is right. This effects performance for all MyBB admin.
This about the function fetch_unread_count() inside inc/functions_indicators.php. This function basically checks to make sure any unread forums will display the indicator that a new posts/thread exists.
I'm investigating this carefully and I find this is only called on one page forumdisplay.php.
Essentially if unread_count returns 0 then the forums are mark read and indicator should be clear. However if it returns 1 or more then we should see the indicator.
But let's review the actual function please.
That's fairly big function but what really catches my eye is the query.
That's a monster. But I have to ask..why is there not a LIMIT command? A LIMIT 1 should greatly increase speed and performance of this query. Because the count only has to be 0 or 1 for the feature to work.
Please examine what I'm stating and if I've made an error in my judgement please let me know.
btw above that query is one with a LIMIT of 100. Why not just make it LIMIT 1?
This about the function fetch_unread_count() inside inc/functions_indicators.php. This function basically checks to make sure any unread forums will display the indicator that a new posts/thread exists.
I'm investigating this carefully and I find this is only called on one page forumdisplay.php.
// If there are no unread threads in this forum and no unread child forums - mark it as read
require_once MYBB_ROOT."inc/functions_indicators.php";
if(fetch_unread_count($fid) == 0 && $unread_forums == 0)
{
mark_forum_read($fid);
}
Essentially if unread_count returns 0 then the forums are mark read and indicator should be clear. However if it returns 1 or more then we should see the indicator.
But let's review the actual function please.
function fetch_unread_count($fid)
{
global $db, $mybb;
$cutoff = TIME_NOW-$mybb->settings['threadreadcut']*60*60*24;
if($mybb->user['uid'] == 0)
{
$comma = '';
$tids = '';
$threadsread = unserialize($mybb->cookies['mybb']['threadread']);
$forumsread = unserialize($mybb->cookies['mybb']['forumread']);
if(is_array($threadsread))
{
foreach($threadsread as $key => $value)
{
$tids .= $comma.intval($key);
$comma = ',';
}
}
if(!empty($tids))
{
$count = 0;
// We set a limit to 100 otherwise it'll become too processor intensive, especially if we have many threads.
$query = $db->query("
SELECT lastpost, tid, fid
FROM ".TABLE_PREFIX."threads
WHERE visible=1 AND closed NOT LIKE 'moved|%' AND fid IN ($fid) AND tid IN ($tids) AND lastpost > '{$cutoff}'
LIMIT 100
");
while($thread = $db->fetch_array($query))
{
if($thread['lastpost'] > intval($threadsread[$thread['tid']]) && $thread['lastpost'] > intval($forumsread[$thread['fid']]))
{
++$count;
}
}
return $count;
}
}
else
{
switch($db->type)
{
case "pgsql":
$query = $db->query("
SELECT COUNT(t.tid) AS unread_count
FROM ".TABLE_PREFIX."threads t
LEFT JOIN ".TABLE_PREFIX."threadsread tr ON (tr.tid=t.tid AND tr.uid='{$mybb->user['uid']}')
LEFT JOIN ".TABLE_PREFIX."forumsread fr ON (fr.fid=t.fid AND fr.uid='{$mybb->user['uid']}')
WHERE t.visible=1 AND t.closed NOT LIKE 'moved|%' AND t.fid IN ($fid) AND t.lastpost > COALESCE(tr.dateline,$cutoff) AND t.lastpost > COALESCE(fr.dateline,$cutoff) AND t.lastpost>$cutoff
");
break;
default:
$query = $db->query("
SELECT COUNT(t.tid) AS unread_count
FROM ".TABLE_PREFIX."threads t
LEFT JOIN ".TABLE_PREFIX."threadsread tr ON (tr.tid=t.tid AND tr.uid='{$mybb->user['uid']}')
LEFT JOIN ".TABLE_PREFIX."forumsread fr ON (fr.fid=t.fid AND fr.uid='{$mybb->user['uid']}')
WHERE t.visible=1 AND t.closed NOT LIKE 'moved|%' AND t.fid IN ($fid) AND t.lastpost > IFNULL(tr.dateline,$cutoff) AND t.lastpost > IFNULL(fr.dateline,$cutoff) AND t.lastpost>$cutoff
");
}
return $db->fetch_field($query, "unread_count");
}
}
That's fairly big function but what really catches my eye is the query.
$query = $db->query("
SELECT COUNT(t.tid) AS unread_count
FROM ".TABLE_PREFIX."threads t
LEFT JOIN ".TABLE_PREFIX."threadsread tr ON (tr.tid=t.tid AND tr.uid='{$mybb->user['uid']}')
LEFT JOIN ".TABLE_PREFIX."forumsread fr ON (fr.fid=t.fid AND fr.uid='{$mybb->user['uid']}')
WHERE t.visible=1 AND t.closed NOT LIKE 'moved|%' AND t.fid IN ($fid) AND t.lastpost > IFNULL(tr.dateline,$cutoff) AND t.lastpost > IFNULL(fr.dateline,$cutoff) AND t.lastpost>$cutoff
");
That's a monster. But I have to ask..why is there not a LIMIT command? A LIMIT 1 should greatly increase speed and performance of this query. Because the count only has to be 0 or 1 for the feature to work.
Please examine what I'm stating and if I've made an error in my judgement please let me know.
btw above that query is one with a LIMIT of 100. Why not just make it LIMIT 1?