我有一个论坛,我有像 - >这样的属性
每个帖子,答案,评论都有follow
,voteup
,votedown
,report
,favorite
,view
等。
哪种方法会更快更好地表现?
我期待数十亿favorite
,views
等......就像youtube
制作一张大表counter
counter_id | user_id | object_id | object_type | property
其中object_type
= thread
,comment
,answer
及其各自id
来自表格threads
,comments
,{ {1}}
和answers
= property
,follow
,voteup
,votedown
等
制作report
,follow
,views
等个别表格
report
views
view_id | user_id | object_id | object_type
follows
答案 0 :(得分:2)
对此没有单一的答案,它非常主观。
最常见的是,最好考虑设计的用例。在将这些字段添加到任何表之前,请仔细考虑这些字段的用途。并且不要认为你必须为每个表添加一个数字主键(" ID")。用于跟踪的表格很好,只有字段user id | object id | object type
和主键中包含的所有三个字段。
你的代码不太可能会被用作youtube甚至堆栈溢出等性能限制。如果是这样的话,那么你很可能会在那时重建数据库。
然而,为了练习,请考虑使用数据的位置和方式......
我会有以下单独的表
<强>按照强> 用户提要,可能需要自己的表,因为它最常被从任何地方点击(有点像全局收件箱)。以下内容还应该有一些标记或时间戳来显示更改,以便在上次用户上线后发生更改时很容易评估.......
这是因为用户需要查看他们所遵循的内容,因为某些Feed和其他人需要查看有多少人关注过。但其他人不需要知道还有谁跟随。
投票,投票 那只是投票和+ - 旗帜。对此进行非规范化...即将用户在表中的个人投票存储起来,并在对象表的字段上存储针对对象的投票计数。这样,您只能检查单个用户的投票(他们拥有)以获取页面视图。从包含内容的同一行中检索计数。
再次。用户需要查看他们上/下投票的内容。你需要检查他们没有投票两次。重要的是最终的计数。因此,检查具有百万票数的对象不应该达到一百万行 - 只需一行。
专业提示:如果您经常更新包含大量内容的行,某些数据库引擎会表现不佳。所以考虑一下&#34;元数据&#34;所有对象的表。哪个商店计数如此。这使得元数据可以自由更新,即使内容不是。
<强>收藏强>
自己的表再次。 user id | object id | object type
。如果您想向公众显示收藏数量,那么请针对该对象保持计数,不要在每个页面查看select count(*)
。
查看强> 为什么甚至存储这个?保持对对象的计数。如果您要存储历史记录,请确保为其添加时间戳并定期清除它。您不需要存储用户六个月前查看的内容。
作为一般观察,所有这些都是单独的表格,但上下投票除外。
您应该对计数进行非规范化,以减少服务器需要访问的数据量,以确定页面视图。最常见的是页面视图应该是最快的。任何形式的更新都可能会慢一点。
我提到收藏夹以及其他人不需要额外的主键字段。我的意思是他们有一个主键,而不是一个额外的字段。例如,收藏夹可以是:
CREATE TABLE favourites (
user INT,
object_type INT,
object_id INT,
PRIMARY KEY (user, object_type, object_id)
)
根本没有理由拥有favorite_id
字段。
答案 1 :(得分:1)
答案,第1部分:计划重新设计。
我能给你的最好建议是计划改变。你设计的第一个百万不会为3000万工作。 3000万的设计将无法生存到十亿。无论你在阅读这个帖子后做了什么,都可以持续30K行。
这是为什么?好吧,部分是因为你无法在一台机器上完成它。不要现在对你的数据库进行分片,但要记住你需要对它进行分片。那时,在一台机器上运行的大部分功能将无法在多台机器上运行,或者运行速度太慢。所以你必须重新设计。
让我指出10亿行的另一个方面。想想你在一年内将表格增长到1B行的速度有多快。它每秒超过30。这是不错的,直到你考虑到将获得的峰值。
如果您的第二个十亿不会适合您已经布置的磁盘,会发生什么?
任何增长到十亿行的人都必须随时学习。教科书不去那里;手册不会去那里;只有销售人员去那里,但在支票清除后他们不会留下来。看看YouTube(等) - 几乎什么都不是#34;现成的#34;。
想想你需要雇佣多少智能设计师来达到10亿。
将列添加到十亿行表是很痛苦的,因此(1)提前计划,以及(2)设计一种在没有重大中断的情况下进行更改的方法。
答案,第2部分:一些提示
以下是我对这些想法的一些评论,以及处理了十亿行分片系统(不是YouTube,但类似的东西)的人的一些提示。
Normalize vs denormalize:我的座右铭:&#34;正常化,但不要过度正常化。&#34;你完成了一些工作后,你会明白我的意思。
一个表与多个表:两个具有基本相同的CREATE TABLE的表应该通常是一个表。 (当然,分片会违反这一点。)OTOH,如果你每秒需要数千UPDATE...view_count = view_count + 1
,它就不会生存到十亿。但是,它可能会存活到一百万;然后计划改变。
最小化数据类型的大小 - 对一列使用MEDIUMINT而不是INT可以节省千兆字节。
不要使用OFFSET和LIMIT进行分页。 (我有一个解决方法的博客。)
尽可能批量插入。
使用InnoDB,您不想等待数小时的时间让REPAIR完成MyISAM表。
为下一个&#39;获取唯一ID的简单任务。 item可能是分片系统中的一个大问题。在重新设计该部分之前,请等待您更接近需要分片。不要将UUID用于十亿行表;他们将表现不佳。所以,现在不要考虑UUID; 将扔掉它们。
在您达到10亿之前很久,您将会遇到关于一台机器崩溃的噩梦。早点考虑复制,HA等。在你有大桌子之后设置这样的东西是痛苦的。