I think it is necessary to de-normaize database for user notifications. For example, when flagging a post (which should be considered by user), we add a column of flag ENUM('yes', 'no') (or status column). Finding flagged events for a user can be by counting with WHERE clause of user_id='XX' AND flag='yes'.
This normalized structure is fine; but what if we have different types of notifications; e.g. flags for posts, comments, photos … This means that we need to count several tables when the user is just visiting his profile page. This is more serious for a cross-project like stackexchange, as we get notifications for different sites.
I think de-normalization can help to add notification columns to the user table as
post_flags tinyint(3),
comment_flags tinyint(3),
photo_flags tinyint(3),
In this case, we need to run an additional write query for updating user flag columns on every corresponding actions. For example, when flagging a post: UPDATE users SET post_flags=post_flags+1 WHERE user_id='XX'. My concern is to ensure execution of the latter query to avoid any mismatch between this number and the count of flagged posts; but I think it can be secured by TRANSACTION.
In this way, we get all notification with one query for frequently visited profile pages.
Am I on the right track? or another tricky approach is common for this purpose?
You’d probably be better off with a table of user notifications.
A separate, narrower table is both logical and (probably) faster. Unsigned for flags, because negative numbers there make no sense, and MySQL doesn’t enforce CHECK constraints.
As far as normalization goes, user_notifications is in 5NF.