#postgresql #database-design #relational-database
Вопрос:
В настоящее время я создаю приложение, похожее на форум. Пользователи смогут просматривать последние сообщения с общим количеством лайков. Если пост интересен пользователю, он также может ему понравиться и внести свой вклад в общее количество лайков.
Нормализованный подход состоял бы в том, чтобы иметь две таблицы: user_post(contains id, metadata ...)
, liked_post(which includes the user id post id)
. Когда сообщения запрашиваются, количество похожих будет определяться с COUNT()
помощью инструкции в liked_post
таблице, сгруппированной по идентификатору сообщения.
Я думаю о другом подходе, который не требует группирования на потенциально огромном столе. Это означало бы добавить like_count
столбец в user_post
таблицу и нарушить нормализацию. Этот столбец всегда будет обновляться, когда будет вставлена или удалена новая запись liked_post. Это означает: Каждый раз, когда пользователю нравится сообщение -> в таблице > будет обновление user_post
(увеличение like_count
столбца) вставка/удаление объекта в liked_post
таблице (с триггером или кодом на уровне приложения).
Будет ли у этого aggregation on the fly
подхода какие-либо недостатки, за исключением проблем согласованности? Это позволило бы выполнять очень простые и быстрые запросы на выбор, но я не уверен, что дополнительное обновление будет проблемой.
О чем вы думаете ? Меня действительно интересует влияние на производительность, а не то, следует ли вам делать это с самого начала проекта или нет.
Комментарии:
1. В PostgreSQL есть эффект раздувания . Поэтому я бы предложил создать еще одну тонкую таблицу всего с двумя столбцами:
post_id
иlike_count
.
Ответ №1:
Ваша идея верна и широко используется. Проблема, с которой вы столкнетесь:
- как вы можете убедиться, что
like_count
это действительно так? Можно ли как-то задержать или приблизить это число?
В общем случае вы можете сделать это следующими способами
- обновите количество лайков в коде приложения
- обновите количество лайков по триггерам
Если вы хотите, чтобы точные значения были правильными, вы можете накапливать эти суммы с помощью триггеров или делать это программно, гарантируя, что обновление like count всегда находится в той же транзакции, что и вставка в liked_posts
Используя триггеры, это может быть что-то вроде этого:
CREATE FUNCTION public.update_like_count() RETURNS trigger
LANGUAGE plpgsql
AS $
BEGIN
UPDATE user_post SET user_post.liked_count = user_post.liked_count 1
WHERE user_post.id = NEW.post_id;
RETURN NEW;
END;
$;
CREATE TRIGGER update_like_counts
AFTER INSERT ON public.liked_posts
FOR EACH ROW EXECUTE PROCEDURE public.update_like_count();
Также вы должны обращаться AFTER DELETE
с отдельным триггером.
Имейте в виду, что в зависимости от уровня изоляции транзакций здесь может возникнуть проблема с параллелизмом (если 2 вставки выполняются одновременно — like_count может быть одинаковым числом для двух транзакций) и в итоге получится недопустимое общее число.
Ответ №2:
Итак, у меня была проблема, похожая на эту в прошлом, решение, с которым я пошел, похоже на то, что вы описали, то есть с агрегированным сохраненным значением like_count
. Как вы упомянули, единственным недостатком будут проблемы с согласованностью, однако эта проблема существует даже в первом случае.
Решение чего-то подобного больше лежит в разработке приложений, поэтому используйте что-то вроде веб-сокетов для обновления сообщений без лишнего шума
Когда браузер/клиент пользователя загружает сообщение, они присоединяются к комнате с идентификатором сообщения, и когда пользователь взаимодействует с сообщением ( нравится, не нравится и т. Д.), Это взаимодействие транслируется всем пользователям в этой комнате ( идентификатор сообщения ).
Наконец, когда дело доходит до выяснения, кому из пользователей понравился этот пост, вы можете запросить/загрузить его в тот момент, когда пользователь нажимает, чтобы узнать. ~ твое здоровье