mysql - 如何为我的网站帖子实现查看系统?

标签 mysql sql algorithm performance database-design

这是我目前的结构:

// 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、nosql 等。同时,让我们看看我们可以用您已有的东西做些什么。

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

INDEX(id, timestamp)

和使用

WHERE id = :id
ORDER BY timestamp DESC
LIMIT 10

任何索引都按索引的内容排序。那就是您要查找的 10 行彼此相邻。即使数据被推出缓存,也可能只有一个 block 来提供这 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 变化如此频繁,以至于这些操作会与 Postings 上的其他事件发生冲突。最好将它们分开。

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

关于mysql - 如何为我的网站帖子实现查看系统?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38287659/

相关文章:

php - 查询车辆的可用租赁日期

php - SQL 选择值匹配的最新行

sql - 尽管有大量可用内存,但 SSIS 内存不足

java - 二进制数组的最小相邻交换数

java - 以编程方式在 TestNG xml 套件中设置测试参数以实现并行执行

mysql - 如何将两个查询的结果与排序结合起来?

mysql - 如果唯一键很长,将 MYISAM 表转换为 INNODB

mysql - 在 SQL 查询中分组

sql - 如何避免隐式转换时出现无效数字

c# - 找到最小数量的墙