Ответ 1
Я склоняюсь к тому, чтобы иметь только таблицу мастер-активности. Если вы пойдете с этим, это то, что я бы рассмотрел при реализации:
-
Вы можете создать несколько таблиц действий и выполнить UNION ALL при извлечении данных из базы данных. Например, сверните их по месяцам - activity_2010_02 и т.д. Просто перейдем к вашему примеру - 200K пользователей x 100 друзей x 3 действия = 60 миллионов строк. Для PostgreSQL это не относится к производительности, но теперь вы можете рассмотреть это исключительно для удобства и в конечном итоге для легкого расширения в будущем.
-
Это имеет тот недостаток, что вы запрашиваете пользователей, которые никогда не могут быть активными, и по мере роста вашего списка друзей этот запрос может замедляться и замедляться.
Собираетесь ли вы отображать весь фид активности, возвращаясь к началу времен? Вы не представили много деталей в исходном вопросе, но я бы рискнул предположить, что вы будете показывать последние 10/20/100 элементов, отсортированных по метке времени. Пара индексов и предложение LIMIT должны быть достаточными, чтобы обеспечить мгновенный отклик (как я только что тестировал на столе с примерно 20 миллионами строк). Он может быть медленнее на занятом сервере, но это то, что должно быть разработано с помощью аппаратных решений и кеширования, Postgres не будет узким местом там.
Даже если вы предоставляете фиды активности, восходящие к рассвету времени, разбивайте выходные данные на страницу! Предложение LIMIT спасет вас там. Если базового запроса с LIMIT на нем недостаточно, или если у ваших пользователей длинный хвост друзей, которые больше не активны, вы можете сначала ограничить поиск до последнего дня/недели/месяца, а затем предоставить список friend id:
select * from activity
where ts <= 123456789
and source_user in (1, 2, 44, 2423, ... my friend list)
Если у вас есть таблица, охватывающая месяцы или годы назад, поиск идентификаторов друзей будет выполняться только в строках, выбранных первым предложением WHERE.
Это просто, если я выберу между двумя решениями, которые вы сейчас рассматриваете. Я также посмотрел бы на такие вещи, как:
-
Пересмотр вашей денормализации таблицы. Является ли сохранение предварительно сгенерированного вывода HTML действительно лучшим способом? Будете ли вы лучше ориентироваться на производительность, имея вместо этого таблицу поиска и генерируя шаблонный вывод "на лету"? Предварительно сгенерированный HTML может показаться лучше с самого начала, но учитывать такие вещи, как дисковое хранилище, API, будущие изменения макета и хранение HTML, возможно, не так привлекательны. Таблица поиска может содержать ваши возможные действия - добавлен друг, измененный статус и т.д., И журнал активности будет ссылаться на этот идентификатор и идентификатор друга, если в этот актив участвует другой пользователь.
-
Выполнение предварительного генерации HTML, но не сохранение его в базе данных. Сохраните материал на диске в виде предварительно сгенерированных страниц. Однако это не серебряная пуля и во многом зависит от соотношения между чтением и чтением на вашем сайте. То есть типичная дискуссионная дискуссия на публичном форуме могла иметь десяток сообщений, но их можно было бы просмотреть сотни раз - хороший кандидат на кеширование. Если ваше приложение больше настроено на немедленные обновления статуса, и вам придется регенерировать HTML-страницу и сохранять ее снова на диске после каждых двух просмотров, тогда в этом подходе мало значения.
Надеюсь, что это поможет.