6

MySQL innoDB 表中都有微博帖子和与之相关的投票/表情符号。需要两种类型的页面:

(A) 包含许多微博的列表页面以及单页上的投票数/表情符号数(例如 25)。

例如

最有趣的帖子

在一个有趣的帖子中没有那么有趣的内容。Lorem ipsum dolor sit amet, consectetur adipiscing elit。Phasellus euismod consequat pellentesque。.....阅读更多....

(3) 喜欢, (5) 无聊, (7) 微笑

. + 同一页面上还有 24 个帖子。

(B) 包含单个微博的永久链接页面,其中包含详细的投票+投票计数/表情符号。

最有趣的帖子

在一个有趣的帖子中没有那么有趣的内容。Lorem ipsum dolor sit amet, consectetur adipiscing elit。Phasellus euismod consequat pellentesque。Quisque viverra adipiscing auctor。Mauris ut diam risus,在发酵菌中。Aliquam urna lectus, egestas sit amet cursus et, auctor ut elit。Nulla tempus suscipit nisi, nec condimentum dui infantum non。在 eget lacus mi, ut placerat nisi。

(你、Derp 和另外1 个这样)、(5) 无聊(7) 笑了

第一种方法:

表格1:

post_id | post_content | post_title | creation_time 

表#2 用于存储投票、喜欢、表情符号:

action_id | post_id | action_type | action_creator | creation_time

显示一页帖子或单个帖子。查询第一个表以获取帖子,第二个查询以获取与帖子相关的所有操作。每当进行投票等时,都会在表中插入一个post_actions

第二种方法:

表格1:

post_id | post_content | post_title | creation_time | action_data 

哪里action_data可以像{ "likes" : 3,"smiles":4 ...}

表#2:

action_id | post_id | action_type | action_creator | creation_time

要显示一页帖子,仅查询第一个表以获取帖子和操作数据,以显示具有详细操作的单个帖子,查询第二个表以获取与帖子相关的所有操作。每当完成投票等操作时,都会在表中进行插入post_actions,并更新 table#1 的 action_data 字段以存储更新后的计数。

假设有 10 万个帖子和 10 倍的操作,即创建了 100 万个或更多操作。方法#2 有好处吗?除了必须读取、修改和更新 JSON 信息之外,它还有什么缺点吗?无论如何可以遵循并进一步改进哪种方法#2?

根据反馈添加更多信息:

  1. Python 脚本将读取、写入数据。
  2. MySQL DB 服务器将不同于 Web 服务器。
  3. 由于帖子创建的写入量很低,即每天 10000 次。但是由于动作引起的可能更高,假设由于投票、喜欢、表情等动作,每秒最多写入 50 次。
  4. 我担心的是两种方法的读/写性能比较和第二种方法的陷阱,以及将来可能会不足的地方。
4

4 回答 4

7

我建议要么将所有喜欢/投票数据(聚合和原子)存储在表 1 中并完全丢弃表 2,要么依赖JOIN语法、智能查询和良好索引的同时使用 2 个没有聚合数据的表。

为什么?因为否则,当您发表评论/投票/喜欢时,您将一直在查询和写入两个表。假设每个帖子有 10 个操作仅用于显示交互,我真的会将它们全部存储到 1 个表中,可能为每种操作创建一个额外的列。您可以使用 JSON 或简单地serialize()在数组上使用,这应该会更快一些。

您最终选择哪种解决方案将在很大程度上取决于您获得多少操作以及您希望如何使用它们。使用解决方案 1 可以轻松获取 1 个帖子的所有操作,而且速度非常快,但在内部搜索会很麻烦。另一方面,解决方案 2 占用更多空间、仔细的查询编写和索引。

于 2012-10-25T14:55:49.100 回答
2

Assuming there are much more reads from the system than writes I can think few ways to do this. You can take advantage of the fact that social networking sites really don't need to have consistent data, only eventually consistent as long as every user sees his/her actions consistently.

Option #1.

Add column for each action type in Table#1 and increment them every time new action happens. In this way the main page listing is very fast.

Table#1

post_id | post_content | post_title | creation_time | action1_count | action2_count | action3_count | ...

What is cool in this approach is that when viewing permalink you don't need to query all actions for post from table#2. Just query last 5 any actions and all actions made by the viewer. Check inspiration here: How to get the latest 2 items per category in one select (with mysql)

Option #2.

This is like your first approach, but write action counts in the Redis hashset or simply as JSON object to memcache. It's lighting fast to query those on main page load. Drawback is that if redis (and always when memcached) is restarted you need to re-initialize them, or just do it when somebody views page from permalink view.

于 2012-10-27T02:20:56.413 回答
2

在一切之前,我会说选项 2 源于过早地尝试优化,除非您已经有统计数据表明在列表页面中没有用于查询的连接会提高性能,否则我会坚持使用选项 1。

选项 2 的主要问题是维护,每次您需要更改某些内容时,您都必须在两个地方进行更改,并且为了修复错误或用新字段填充旧记录,在您发布的所有帖子上必须在数据库端(通常)执行字符串操作。

根据我的经验,选项 2 在性能方面的好处将是微乎其微的,查询数据库(至少是这样短的查询)时的大部分延迟将来自连接到远程服务器。

此外,如果您正确抽象查询,在两种方法之间移动(或使用另一种方法,例如缓存最常见的条目)将很容易,首先使用最简单的方法(即选项 1)然后更改当您获得有关当前实施问题的信息时(这不太可能是您现在认为的那样)。

为清楚起见,这里列出了选项 1 的优点和缺点(与选项 2 相反):

选项1

优点

  • 更快的写入。
  • 更容易维护
  • 较小的存​​储要求
  • 无数据重复

缺点

  • 列表读取速度较慢。
于 2012-10-28T06:52:33.490 回答
-1

重要的一件事是插入/删除/更新之间的性能差异。插入比删除/更新快得多。因此,我会选择一个最小化删除/更新的解决方案。

表 #1 看起来像第一个选项:
post_id | post_content | post_title | creation_time

表 #2 几乎相同,没有action_id.
post_id | action_type | action_creator | creation_time

表 2 将在 post_id、action_type 和 action_creator 列中具有地图复合索引。

地图复合索引的二阶对于快速查询很重要。因为即使不是索引的所有部分都被使用,索引也会如此。那就是下面的查询可以工作 select ... from table_2 where post_id = 1 and action_type = 2
,但下面的查询不会
select ... from table_2 where post_id = 1 and action_creator = 2

快速解释一下,要使用地图复合索引,它就像一棵树,您需要使用树中的所有部分。即不查询 post_id 和 action_type 就无法查询“action_creator”来使用索引。

-post_id  
    |--action_type  
          |--action_creator             

但是,现在您可以进行查询并始终点击复合索引,而且您主要对表#1 和表#2 进行插入。

如果由于大量“操作”而最终得到一个巨大的表 #2,则您可以在将来对 post_id 分区的表进行分区。在您的大部分时间里,您的用户会点击较新的条目,因此您可以“优先考虑”一个具有更快磁盘和数据库中更大内存缓存的分区。或者稍后在数据库前面使用http://memcached.org/之类的东西进行优化。

于 2012-10-28T12:01:25.423 回答