【问题标题】:How can I implement a viewed system for my website's posts?如何为我的网站帖子实施查看系统?
【发布时间】:2016-11-12 06:17:49
【问题描述】:

这是我目前的结构:

// posts
+----+--------+----------+-----------+------------+
| id | title  | content  | author_id | date_time  |
+----+--------+----------+-----------+------------+
| 1  | title1 | content1 | 435       | 1468111492 |
| 2  | title2 | content2 | 657       | 1468113910 |
| 3  | title3 | content3 | 712       | 1468113791 |
+----+--------+----------+-----------+------------+

// viewed
+----+---------------+---------+------------+
| id | user_id_or_ip | post_id | date_tiem  |
+----+---------------+---------+------------+
| 1  | 324           | 1       | 1468111493 |
| 2  | 546           | 3       | 1468111661 |
| 3  | 135.54.12.1   | 1       | 1468111691 |
| 5  | 75            | 1       | 1468112342 |
| 6  | 56.26.32.1    | 2       | 1468113190 |
| 7  | 56.26.32.1    | 3       | 1468113194 |
| 5  | 75            | 2       | 1468112612 |
+----+---------------+---------+------------+

这是我的查询:

SELECT p.*,
       (SELECT count(*) FROM viewed WHERE post_id = :id) AS total_viewed
 FROM posts p
WHERE id = :id

目前我面临viewed 表的巨大约会。那么我的表结构(或数据库设计)有什么问题?换句话说,我该如何改进它?

像 stackoverflow 这样的网站有近 1200 万个帖子。每个帖子有(平均) 500 次查看。所以viewed的行数应该是:

12000000 * 500 = 6,000,000,000 rows

:-) .. 老实说,我什至看不懂那个数字(顺便说一句,这个数字会每秒增长)。那么stackoverflow如何处理每个帖子的查看次数?每次显示的帖子都会从viewed 计算count(*) 吗?

【问题讨论】:

  • 好问题,您需要查看的是内存存储 (Redis),并且每次有人打开帖子时都不会计算 count(*),而是与此内存相关的密钥递增,然后每隔一段时间添加到表中
  • @YehiaAwad 所以我需要像 Redis 这样的无 sql 数据库来处理这个问题?
  • 一个问题可以有一个整数,比如,查看次数。对某个问题的操作(例如某种类型的投票)可以在相交或Junction Table 中。 900M 人可以查看这个问题(我希望他们不会),并且它可能会在此过程中增加一个 view count int。不必添加任何行。然后是分区。

标签: mysql sql algorithm performance database-design


【解决方案1】:

在您拥有数百万行之前,您不太可能需要分区、redis、nosql 等。同时,让我们看看我们能用你所拥有的东西做些什么。

让我们从剖析您的查询开始。我看到了WHERE id=...,但没有看到LIMITORDER BY。让我们添加到您的表中

INDEX(id, timestamp)

并使用

WHERE id = :id
ORDER BY timestamp DESC
LIMIT 10

任何索引都按索引的内容排序。也就是说,您要查找的 10 行彼此相邻。即使数据被推出缓存,也可能只有一个块来提供这 10 行。

但是 InnoDB 二级索引中的“行”不包含满足SELECT * 的数据。索引“行”包含指向实际“数据”行的指针。因此,将有 10 次查找来获取它们。

至于查看次数,让我们以不同的方式实现:

CREATE TABLE ViewCounts (
    post_id ...,
    ct MEDIUMINT UNSIGNED NOT NULL,
    PRIMARY KEY post_id
) ENGINE=InnoDB;

现在,给定post_id,向下钻取 BTree 以查找计数非常有效。 JOINing 这个表到另一个,我们通过另外 10 次查找得到个人计数。

所以,你说,“为什么不把它们放在同一张桌子上”?原因是ViewCounts 变化如此频繁,以至于这些操作会与帖子上的其他活动发生冲突。最好将它们分开。

即使我们命中了几十个块,与扫描数百万行相比,这还不错。而且,这种数据有点“可缓存”。最近的帖子被更频繁地访问。热门用户访问频率更高。因此,100GB 的数据可以充分缓存在 10GB 的 RAM 中。扩展就是“计算磁盘命中数”。

【讨论】:

    猜你喜欢
    • 2012-12-30
    • 1970-01-01
    • 1970-01-01
    • 2011-11-08
    • 1970-01-01
    • 1970-01-01
    • 2017-02-28
    • 1970-01-01
    • 2013-01-10
    相关资源
    最近更新 更多