Topic: SQL Statement optimization
I'm working on a really "new posts" thing, instead of the "since last visit" stuff.
Anyways... Here's the line, and it works... but I'm wondering if there's a better way of making it (read: optimize for speed and memory usage). It's from search.php below "if ($action == 'show_new')"
$result = $db->query('SELECT t.id FROM '.$db->prefix.'topics AS t INNER JOIN '.$db->prefix.'forums AS f ON f.id=t.forum_id LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND NOT EXISTS (SELECT pr.tid FROM posts_read AS pr WHERE pr.tid=t.id AND pr.uid='.$pun_user['id'].')') or error('Unable to fetch topic list', __FILE__, __LINE__, $db->error());
The only thing I've done is add a table, "posts_read (uid INTEGER, tid INTEGER)" uid is the user id of someone who has read the tid, and the tid is you guessed it, the topic id. What happends (or will happen, soon as I finish up) is as viewtopic.php is run, a (uid, tid) pair is added to the table (if it doesn't already exist). As new topics are created nothing need be done. When search.php?action=show_new is run, only the topic id's that the user is allowed to see are returned, and only if the (uid tid) pair for that topic doesn't already exist.
I'm also thinking of inverting it, so that as new messages are created every user get's a (uid, tid) pair added to the posts_read table (or posts_unread, in that case). In the inverted sence, finding new posts would be relatively fast ("SELECT t.* FROM topics AS t INNER JOIN posts_unread AS p LEFT JOIN (permission stuffs) WHERE (more permission stuff) p.uid=CUR_USER_ID p.tid=t.id") and removing the "new post" status would be fast too "DELETE FROM posts_unread WHERE uid=CUR_UID and tid=CUR_TID". There are two downsides to this, the obvious one, new topic meens NUM_OF_REGISTERED_USERS entries created in the database, new posts, same thing, edits, same thing. Then the less obvious... as the number of inactive members grows, the size of the database starts to grow.
Another way would be to have a (uid, tid, timelastviewed); but you wouldn't be able to read the first 3 posts and leave the forth and fifth unread...