There would be a quick hit to simplify this, your original design too overhauled.
Using this solution, your web page can now simply call the following stored procedure to get a list of filtered messages for a given user for a specified period.
call list_user_filtered_posts( <user_id>, <day_interval> );
The whole script can be found here: http://pastie.org/1212812
I have not fully tested all of this, and you may find that this solution is not effective enough for your needs, but it can help you fine-tune / modify the existing design.
Tables
Drop your post_privacy_exclude_from table and add a user_stalkers table, which works almost the same as the back of user_friends. We kept the original post_privacy_includes_for table according to your design, as this allows the user to restrict a specific record to a subset of people.
drop table if exists users; create table users ( user_id int unsigned not null auto_increment primary key, username varbinary(32) unique not null ) engine=innodb; drop table if exists user_friends; create table user_friends ( user_id int unsigned not null, friend_user_id int unsigned not null, primary key (user_id, friend_user_id) ) engine=innodb; drop table if exists user_stalkers; create table user_stalkers ( user_id int unsigned not null, stalker_user_id int unsigned not null, primary key (user_id, stalker_user_id) ) engine=innodb; drop table if exists posts; create table posts ( post_id int unsigned not null auto_increment primary key, user_id int unsigned not null, privacy_level tinyint unsigned not null default 0, post_date datetime not null, key user_idx(user_id), key post_date_user_idx(post_date, user_id) ) engine=innodb; drop table if exists post_privacy_includes_for; create table post_privacy_includes_for ( post_id int unsigned not null, user_id int unsigned not null, primary key (post_id, user_id) ) engine=innodb;
Saved Procedures
The stored procedure is relatively simple - first it selects ALL records for the specified period, and then filters the messages according to your initial requirements. I have not tested this sproc with large volumes, but since the initial choice is relatively small, it should be strong enough, and also simplify your application / mid-level code.
drop procedure if exists list_user_filtered_posts; delimiter
Test Data
Some basic test data.
insert into users (username) values ('f00'),('bar'),('alpha'),('beta'),('gamma'),('omega'); insert into user_friends values (1,2),(1,3),(1,5), (2,1),(2,3),(2,4), (3,1),(3,2), (4,5), (5,1),(5,4); insert into user_stalkers values (4,1); insert into posts (user_id, privacy_level, post_date) values
Testing
As I mentioned earlier, I did not fully test this, but on the surface it seems to work.
select * from posts; call list_user_filtered_posts(1,14); call list_user_filtered_posts(6,14); call list_user_filtered_posts(1,7); call list_user_filtered_posts(6,7);
Hope you find some of these features.