许多小 mysql table 或一大 table

Lots of small mysql table or one big table

我有一个论坛,我有像这样的属性 - > followvoteupvotedownreportfavoriteview 等每个主题、答案、评论。

哪种方法性能更快更好? 我期待数十亿 favoriteviews 等....就像 youtube

方法一

做大一个tablecounter

counter_id | user_id | object_id | object_type | property

其中 object_type = threadcommentanswer 以及来自 table 的 threads 各自的 idcomments,answers

property = follow,voteup,votedown,report

方法二

制作 followviewsreport 等 table 个

这个问题没有唯一的答案,它很主观。

最常见的是,最好考虑设计的用例。在将这些字段添加到任何 table 之前,请仔细考虑这些字段的用途。并且不要认为您必须向每个 table 添加数字主键 ("ID")。用于跟踪的 table 仅适用于字段 user id | object id | object type 和主键中包含的所有三个字段。

您的代码不太可能会在诸如 youtube 甚至堆栈溢出等性能限制下使用。如果是,那么您很可能已经对数据库进行了改造。

但是,为了练习起见,请考虑在何处以及如何使用数据...

我会像下面这样分开 tables

关注 用户提要可能需要自己的 table,因为最常见的是它会从任何地方(有点像全球收件箱)被点击。下面还应该有一些标志或时间戳来显示更改,以便很容易评估自用户上次在线以来发生更改的时间......

这是因为用户需要查看他们作为某种提要关注的内容,而其他用户需要查看有多少人关注了。但是其他人不需要看还有谁关注了。

投赞成票,投反对票 那只是投票和一个 +- 标志。对此进行非规范化...即在 table 中存储用户的个人投票,并在 object 的 table 的字段上存储反对 object 的票数.这样一来,您只会检查单个用户(他们自己)的页面视图投票。从包含内容的同一行检索计数。

再次。用户需要查看他们 up/down 投票的内容。您需要检查他们没有投票两次。重要的是最后的计数。因此,检查 object 一百万票不应该达到一百万行 - 只需一个。

专业提示:如果您不断更新包含大量内容的行,某些数据库引擎的性能会很差。因此,为所有 object 考虑一个 "meta-data" table。哪些商店算这样。这使得元数据可以自由地频繁更新,即使内容没有。

收藏夹 再次拥有 table。 user id | object id | object type。如果您想向 public 显示收藏夹的数量,请针对 object 进行计数,不要在每次页面查看时都执行 select count(*)

查看 为什么还要存储这个?计算 object。如果您要存储历史记录,请确保为其添加时间戳并定期清除它。您不需要存储用户六个月前查看的内容。


作为一般观察,除了赞成票和反对票外,所有这些都是独立的 table。

您应该对计数进行非规范化,以减少服务器需要访问以确定页面视图的数据量。最常见的页面视图应该是最快的。任何形式的更新都可能会慢一点。


我提到 favorites 和其他人不需要额外的主键字段。我的意思是他们有一个主键,而不是一个额外的字段。例如收藏夹可以是:

CREATE TABLE favourites (
    user INT,
    object_type INT,
    object_id INT,
    PRIMARY KEY (user, object_type, object_id)
) 

根本没有理由拥有 favorite_id 字段。

答案,第 1 部分:边走边计划重新设计。

我能给你的最好建议是为改变做计划。你为第一百万人设计的东西不会为三千万人工作。 3000万的设计活不过10亿。阅读此线程后无论您做什么,都可能会持续 30K 行。

这是为什么?好吧,部分原因是您将无法在一台机器上完成它。现在不要对数据库进行分片,但请牢记您需要对其进行分片。到那时,许多在一台机器上工作的东西要么不能在多台机器上工作,要么太慢而无法工作。所以你将不得不重新设计。

让我指出 10 亿行的另一个方面。想一想在 1 年内将 table 行增加到 1B 行需要多快。每秒超过30个。这还不错,直到你考虑到你 得到的尖峰。

如果您布置的磁盘放不下您的第二个十亿会怎样?

任何增长到十亿行的人都必须边学边学。教科书不去那里;手册不在那里;只有推销员去那里,但支票结清后他们不会留下来。看看 YouTube(等)——几乎什么都没有 "off the shelf"。

想想你需要雇佣多少聪明的设计师才能达到 10 亿。

向十亿行添加一列是很痛苦的 table,因此 (1) 提前计划,并且 (2) 设计一种在不造成重大中断的情况下进行更改的方法。

答案,第 2 部分:一些提示

以下是我对反复出现的想法的一些评论,以及来自处理过十亿行分片系统(不是 YouTube,而是类似系统)的人的一些提示。

规范化与非规范化:我的座右铭:"Normalize, but don't overnormalize."你会在你完成一些之后明白我的意思。

一个 table 与多个:具有基本相同 CREATE TABLE 的两个 table 应该 通常 是一个 table。 (当然,分片违反了这一点。)OTOH,如果您每秒需要数千 UPDATE...view_count = view_count + 1,它就无法存活到十亿。但是,它可能会存活到一百万;然后计划改变。

最小化数据类型的大小 -- 对一列使用 MEDIUMINT 而不是 INT 可以节省 1 GB。

不要使用 OFFSET 和 LIMIT 进行分页。 (我有一篇关于解决方法的博客。)

尽可能批量插入。

使用 InnoDB,您不想等待数小时才能在 MyISAM 上完成修复 table。

为 'next' 项获取唯一 ID 的简单任务在分片系统中可能是一个大问题。等到您接近需要分片时再重新设计该部分。不要对十亿行使用 UUID table;他们表现不佳。所以,现在甚至不要考虑 UUID;你把它们扔掉。

早在你达到 10 亿之前,你就会做关于一台机器崩溃的噩梦。尽早考虑复制、HA 等。在你有大 tables 之后设置这样的东西很痛苦。