Агрегировать данные при вставке в необработанную таблицу

#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 . Как вы упомянули, единственным недостатком будут проблемы с согласованностью, однако эта проблема существует даже в первом случае.

Решение чего-то подобного больше лежит в разработке приложений, поэтому используйте что-то вроде веб-сокетов для обновления сообщений без лишнего шума

Когда браузер/клиент пользователя загружает сообщение, они присоединяются к комнате с идентификатором сообщения, и когда пользователь взаимодействует с сообщением ( нравится, не нравится и т. Д.), Это взаимодействие транслируется всем пользователям в этой комнате ( идентификатор сообщения ).

Наконец, когда дело доходит до выяснения, кому из пользователей понравился этот пост, вы можете запросить/загрузить его в тот момент, когда пользователь нажимает, чтобы узнать. ~ твое здоровье