Хм, несколько соображений:
1. — доступно друзьям
— доступно конкретному другу/списку друзей
по сути одно и то же. «доступно друзьям» = «Доступно списку друзей, совпадающему с френд-листом». возможно дешевле будет хранить две копии списка друзей, одна во френд-листе, одна в таких, денормализация — это вовсе не всегда плохо.
2. OR в запросе — прощай индекс. Почему не использовать юнион и два раза доступ по разным индексам? Один раз все публичные записи, второй — для списка друзей. Публичность хранить отдельным столбцом в content — не самое элегантное, но самое простое.
ИЛИ
создаем такую структуру:
table groups
(id_group number,
id_user number,
id_friend number);
table permissions
(id_permission number,
id_content number,
id_group number);
В таблице user указать «дефолтную» группу, совпадающую с френд-листом, соответственно ее обновлять.
Каждое новое разрешение «другу или списку» порождает новую группу и новый пермишен, разрешение «друзьям» — запись в permissions с указанием на дефолтную группу.
Запись в permissions без группы значит «доступно всем».
И делаем так:
SELECT *
FROM content
WHERE id IN (SELECT p.id_content
FROM permissions p
LEFT JOIN groups g ON p.group = g.id
WHERE g.friend = #me#);