【问题标题】:Choose the best way to get the number of comments for posts from Mysql选择从 Mysql 获取帖子评论数的最佳方式
【发布时间】:2020-05-06 06:25:31
【问题描述】:


我有一个关于在数据库中选择表设计的偏好的问题。
首先,我有三个表,分别用于用户、帖子、评论
此模式显示表:
此用户架构:

    CREATE TABLE `Users` (
      `id` int(11) NOT NULL,
      `fullname` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
      `profileImg` varchar(255) DEFAULT NULL,
      `appPackage` varchar(50) DEFAULT NULL,
      `email` varchar(255) NOT NULL,
      `token` text NOT NULL,
      `gender` enum('male','female') DEFAULT NULL,
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

  ALTER TABLE `Users`
  ADD PRIMARY KEY (`id`),
  ADD UNIQUE KEY `email` (`email`);

此帖子架构:

    CREATE TABLE `Posts` (
      `id` int(11) NOT NULL,
      `userId` int(11) NOT NULL,
      `text` varchar(255) COLLATE utf8mb4_bin NOT NULL,
      `background` varchar(10) COLLATE utf8mb4_bin DEFAULT NULL,
      `img` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
      `country` varchar(25) COLLATE utf8mb4_bin DEFAULT NULL,
      `countryCode` varchar(2) COLLATE utf8mb4_bin DEFAULT NULL,
      `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
      `CommentsCount` int(11) NOT NULL,
      `likes` int(11) NOT NULL DEFAULT '0',
      `views` int(11) NOT NULL DEFAULT '0'
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

   ALTER TABLE `Posts`
     ADD PRIMARY KEY (`id`),
     ADD KEY `users_post_userId_fk` (`userId`);

这个 cmets 架构:

CREATE TABLE `Comments` (
  `id` int(11) NOT NULL,
  `postId` int(11) NOT NULL,
  `userId` int(11) NOT NULL,
  `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `commentText` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE `Comments`
  ADD PRIMARY KEY (`id`),
  ADD KEY `users_comments_userId_fk` (`userId`),
  ADD KEY `users_comments_postId_fk` (`postId`);

我想查询 Posts 表,每次查询都会为每个帖子带来 10 行 cmets 计数。
哪个是最好的选择?
通过加入查询 Posts 表以获得这样的 cmets 计数:

SELECT * ,
       (SELECT COUNT(*)
        FROM Comments
        WHERE Comments.postId = Posts.id) AS commentsCount
FROM Posts
ORDER BY Posts.id DESC
LIMIT 0,10

或者在帖子表中创建一个列commentsCount,其中包含每个帖子的 cmets 数。

并创建一个链接到 cmets 表的触发器,其中,当插入新评论时,cmetsCount 中的一个数字会增加,而当删除评论时,commentsCount 中的一个数字会减少。

查询变成只有一个posts表来获取posts和comment count:

SELECT * FROM Posts ORDER BY Posts.id DESC LIMIT 0,10

提前致谢!

【问题讨论】:

  • 请将表格的架构发布为文本,而不是图像。否则,我们无法复制/粘贴来重建表格
  • 简答:用查询来做。计算得到的应该是计算得到的。否则,您正在复制信息。 DRY !

标签: mysql sql database


【解决方案1】:

我建议不要将派生信息存储在post 表中。这将违背规范化的最佳实践(并且维护起来会很痛苦)。

有关 cmets 的信息属于它们自己的表。每当您需要计算每个帖子的 cmets 数量时,您可以按照您的建议使用相关子查询:

SELECT 
    p.* ,
       (SELECT COUNT(*) FROM Comments c WHERE Comments.postId = Posts.id) AS commentsCount
FROM Posts p
ORDER BY p.id DESC
LIMIT 0,10

但是,如果您要处理大量帖子,这可能会变得低效,因此您也可以在 join Posts 表上对 Comments 进行聚合查询,如下所示:

SELECT p.*, COALESCE(c.commentsCount, 0) commentsCount
FROM Posts p
LEFT JOIN (
    SELECT postId, COUNT(*) commentsCount
    FROM Comments
    GROUP BY postId
) c ON c.postId = p.id
ORDER BY p.id DESC
LIMIT 0,10

【讨论】:

  • 感谢您的回答,但我想知道我关于触发器的建议是否有效,还是无效?
  • @Sy4tech:是的,触发器会起作用,但出于上述原因,我建议不要这样做......
【解决方案2】:

两种变体各有利弊:

  • 添加另一个列会破坏标准格式。这不仅仅是理论上的问题:posts 表上的写入负载将急剧增加。
  • 每次计算帖子数确实会产生相当大的负载,但这是一个非常干净的选择。

两者都可以在中等数量的帖子和 cmets 上正常工作,但如果您扩大到更高的帖子/评论频率,我建议您探索不同的方法:

  • 使用空灵但快速的缓存(例如 memcached)来存储帖子计数。
  • 如果有帖子进来,忽略缓存
  • 如果有评论进入(或被删除),只需删除该帖子的缓存项
  • 如果请求评论计数,请查看缓存 - 如果不存在,请计算并将其放入缓存中。
  • 您可以使用内置的过期机制将评论计数缓存保持在可管理的大小,同时仍然具有非常高的命中率。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-01
    • 2015-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-09
    • 2015-03-04
    相关资源
    最近更新 更多