【问题标题】:Aggregate data while inserting into raw table在插入原始表时聚合数据
【发布时间】:2021-08-23 20:13:22
【问题描述】:

我目前正在构建一个类似论坛的应用程序。用户将能够查看具有总点赞数的最近帖子。如果用户对帖子感兴趣,他们也可以喜欢它并为总点赞数做出贡献。

标准化的方法是有两个表:user_post(contains id, metadata ...)liked_post(which includes the user id + post id)。当帖子被查询时,点赞数将由liked_post 表上的COUNT() 语句确定,该表按帖子ID 分组。

我正在考虑另一种方法,它不需要在潜在的大桌子上进行分组。那就是在user_post 表中添加一个like_count 列并打破规范化。当插入或删除新的 like_post 条目时,此列将始终更新。这意味着:每次用户喜欢帖子时 -> 将更新 user_post 表(增加 like_count 列)+ 在 liked_post 表中插入/删除实体(使用应用层中的触发器或代码)。

除了一致性问题之外,这种aggregation on the fly 方法是否有任何缺点?这将启用非常简单和快速的选择查询,但我不确定额外的更新是否会成为问题。

你有什么想法? 我真的对性能影响感兴趣,而不是你是否应该从项目开始就这样做。

【问题讨论】:

  • PostgreSQL 中有bloat 效果。所以我建议再创建一个只有两列的薄表:post_idlike_count

标签: postgresql database-design relational-database


【解决方案1】:

你的想法是正确的并且被广泛使用。您将面临的问题:

  • 如何确保like_count 有效?这个数字能否以某种方式延迟或近似?

一般来说,你可以通过以下方式做到这一点

  • 更新应用代码中的like_count
  • 通过触发器更新like_count

如果您想获得正确的准确值,您可以通过触发器累积这些总和,或者以编程方式进行,以确保类似计数更新始终在插入到 like_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。就像您提到的那样,唯一的缺点是一致性问题,但是即使在前者中也存在这个问题。

    此类问题的解决方案更多地在于应用程序开发,因此利用 web-sockets 之类的东西来保持帖子的最新状态,而不会有太多的毛茸茸

    当用户的浏览器/客户端加载帖子时,他们会使用帖子 ID 加入房间,并且当用户与帖子交互(喜欢、不喜欢等)时,该交互会广播给该房间中的所有用户(帖子 ID)。

    最后,当要找出哪些用户喜欢这篇文章时,您可以在用户点击时进行查询/加载。 ~ 干杯

    【讨论】:

      猜你喜欢
      • 2017-07-18
      • 2021-12-28
      • 2019-05-27
      • 1970-01-01
      • 1970-01-01
      • 2021-03-12
      • 1970-01-01
      • 2011-06-29
      • 1970-01-01
      相关资源
      最近更新 更多