Здравствуйте. Нужна ваша подсказка в оптимизации запроса или советы по изменению структуры БД. Прошу прощения, что написал в этот форум, но тут много умных людей, надеюсь на вашу помощь.
Задача: есть таблица с пользователями, их дружбой, есть сообщения. Нужно вывести пользователю с user_id 30 последних сообщений, которые соответствуют схеме: его сообщения, все сообщения его друзей которые написаны сами по себе (parent_message_id = 0) и сообщения друзей, написанные вашим взаимным друзьям.
parent_message_id - id родительского сообщения op_user_id - id пользователя в ответ на которое написано данное сообщение
Мой вариант решения был такой:
1. Получаем моих друзей (user_friends)
SELECT * FROM message
JOIN
user ON (user.user_id = message.user_id)
LEFT JOIN
user AS op_user ON (op_user.user_id = message.op_user_id)
WHERE
user_id = $self.user_id^if($user_friends){OR (user_id IN (^foreach[$user_friends;f]{$f.friend_user_id}[,]) AND op_user_id IN (0, $self.user_id^foreach[$user_friends;f]{, $f.friend_user_id}))}
Да, OR использовать в выражении плохо. Можно заменить на 2 запроса SELECT через JOIN.
Но вот что делать с большим кол-вом user_friends. Т.к. кол-во дружб может быть и 50000 (что уже есть).
Подскажите вариант по оптимизации, очень нужен совет.
Первое что приходит в голову: в таблицу юзера писать дату его последнего сообщения. И выбирать (для построения запроса к сообщениям) не всех друзей, а только тех кто недавно писал (с нужным лимитом).
Я имел ввиду, что кол-во друзей отсортированных по дате сообщения (по убыванию) -- будет равно кол-ву сообщений которые нужно отобразить в ленте. таким образом из 50 тысяч остается то количество которое нужно для ленты.
Небольшая сложность в другом: и сообщения друзей, написанные вашим взаимным друзьям. тоесть выводим вовсе не все сообщения друзей. и тут вариант с датой последнего сообщения не прокатит - так как последнее сообщение друга может быть адресовано юзеру который не является взаимным.
P.S. В твиттере используют кассандру и свою собственную flockDB для хранения графов.
В статье предлагается генерировать ленты сообщений для каждого пользователя при написании сообщения.
Вопрос в том насколько это оправдано. Если учитывать что это будет делаться в фоновом режиме, то и 50000 не должно стать проблемой. А если это 5 миллионов.
Вполне логичное решение для обхода проблемы с тяжелыми выборками. Из минусов остается лишь избыточность данных. это означает что стоит заранее продумать возможность горизонтального масштабирования.
Вопрос в том насколько это оправдано. Если учитывать что это будет делаться в фоновом режиме, то и 50000 не должно стать проблемой. А если это 5 миллионов. Вполне оправдано если проект в этом нуждается. 5 миллионов апдейтов будут выполнятся чуть дольше чем 50 000 вот и все. тут должна пригодится репликация master-slave. Тему AMQP, который идеально подходит для решения задачи доставки информации о событиях пользователям, можно вообще развить и использовать не только для фоновых операций, а сделать очереди для каждого пользователя, например.
Вообще я не спец по оптимизации таких крупных систем, но считаю что решать проблемы оптимизации стоит решать по мере их поступления (впрочем это неизбежно). Так как, всех сложностей, с которыми столкнется проект в жизни, предугадать сложно. Да и оно может того не стоить если проект не поплывет. Однако, это не отменяет проектирование грамотной архитектуры на раннем этапе.
Там больше об используемых технологиях, нежели о детализации архитектуры
Про Digg в свое время было больше статей и более детальные. Они писали про проблемы масштабирования, с которыми сталкивались. Про твиттер, к сожалению, почти ничего нет.