类似 Twitter 的帖子时间线的数据库结构和查询

Posted

技术标签:

【中文标题】类似 Twitter 的帖子时间线的数据库结构和查询【英文标题】:Database structure and queries for a Twitter-like posts timeline 【发布时间】:2017-05-18 03:07:25 【问题描述】:

我用 Django 标签发布这个问题,因为我在这个环境中工作,但它实际上更像是一个通用问题:我想在 Twitter 上显示我的时间线之类的东西,即帖子列表在我关注的所有人中按时间顺序排列。

我的典型数据库结构如下所示:

Table Name: Users
Columns:
    UserID PK
    EmailAddress
    Password

TableName: Friends
Columns:
    UserID PK FK
    FriendID PK FK

TableName: Posts
Columns:
    UserID PK FK
    Content

如果我想检索给定用户的所有朋友的所有帖子,它看起来像这样(这不应该是有效的 SQL!):

SELECT * FROM Posts WHERE UserID IN (LIST OF "Given user friends' IDs")

这行得通 - 没问题!但是,这确实无法扩展!假设我们有一个繁忙的网站,给定的用户有 2,000 个朋友,并且数据库中有大约 1000 万个帖子。在这种情况下,数据库查询将非常低效且缓慢。

可以使用 PostgreSQL 或 mysql 之类的关系数据库来解决这个问题吗?如果没有,例如如何推特做到了吗?

【问题讨论】:

【参考方案1】:
   SELECT p.*
     FROM Posts AS p
     JOIN (SELECT FriendID
             FROM Friends
            WHERE UserID = :given_user_id) AS f
       ON (p.UserID = f.FriendID)

扩展性更好。当你标记了你的 PK 时,你已经有了所有需要的索引。

【讨论】:

【参考方案2】:

更短的版本:

SELECT
    Posts.*
FROM
    Posts 
    JOIN Friends ON Friends.FriendID = Posts.UserID
WHERE
    Friends.UserID = 1 /* change as needed */ ;

您可以通过以下方式进行检查:

CREATE TABLE Users
(
    UserID integer PRIMARY KEY,
    EmailAddress text,
    Password text
) ;

CREATE TABLE Friends
(
    UserID integer NOT NULL REFERENCES Users(UserID),
    FriendID integer NOT NULL REFERENCES Users(UserID),
    PRIMARY KEY (UserID, FriendID)
) ;

CREATE TABLE Posts
(
    PostID integer PRIMARY KEY,
    UserID integer NOT NULL REFERENCES Users(UserID),
    Content text
) ;

INSERT INTO Users 
VALUES 
  (1, 'a@b.com', 'pass1'),
  (2, 'b@b.com', 'pass2'),
  (3, 'c@b.com', 'pass3'),
  (4, 'd@b.com', 'pass4') ;

INSERT INTO Friends
VALUES 
   (1, 2),
   (1, 4) ;

INSERT INTO Posts
VALUES
    (1, 2, 'A post from User 2'),
    (2, 2, 'Another post from User 2'),
    (3, 3, 'A post from User 3'),
    (4, 4, 'A post from User 4') ;

你应该得到:

+---+---+--------------------------+
| 1 | 2 | A post from User 2       |
| 2 | 2 | Another post from User 2 |
| 4 | 4 | A post from User 4       |
+---+---+--------------------------+

【讨论】:

谢谢乔阿诺洛!我已将您的答案标记为正确,因为您给出了一个完整的示例。其他答案同样正确。然而,我希望有一个类似于 NoSQL 数据库的更复杂的解决方案,因为 JOIN 仍然不够高效。我是 Pixabay.com 的首席开发人员 - 我们的 PostgreSQL 数据库越来越多地变成可靠的数据存储,而所有快速读取的数据都由 Elastisearch 服务器提供服务。它正在工作,但我想知道 NoSQL 数据库是否是另一种方法。 Twitter 或 Facebook 是如何做到的? 您需要两个表中的信息。你必须以一种或另一种方式join他们。让数据库决定哪种方法是最好的。 NoSQL 数据库非常适合存储整个文档(例如:一篇文章及其所有 cmets,它们总是一起显示)。执行 join (这是你想要的)通常不是很好。您可能只需要一个 更快 的数据库(更快的硬件、SSD 磁盘、大量内存,以便您的大部分数据适合 RAM,...)。并确保您拥有所有正确的索引。可以发一份执行计划吗? WRT 对 Twitter 和 Facebook 所做的事情:我真的不知道(而且我认为他们不会公开此信息)。但我认为他们只是使用了一些技术,为他们提供了一个近似解决方案。 BTW:拥有 2000 个朋友的用户现实吗?如果您的问题与朋友的网络密切相关,您可能需要查看graph databases(例如Neo4J)。 哦,图数据库,没听说过。对于这个用例来说,这听起来像是一个有趣的选择。谢谢 - 还有关于 NoSQL 的解释!【参考方案3】:

您也可以按照自己的QUERY,它会工作:

SELECT
    *
FROM
    Posts
WHERE
    UserID in (SELECT FriendID 
                 FROM Friends 
                WHERE UserID = 1 /* whatever */ ) ;

这将扩展(在最新版本的 mySQL 或 PostgreSQL 中,它将生成与 JOIN 相同的执行计划)。

【讨论】:

以上是关于类似 Twitter 的帖子时间线的数据库结构和查询的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 django 制作类似 twitter 的主页?

如何在原生 iOS 应用中显示 Facebook 帖子?

类似 Twitter 设计结构的 iPhone 应用

Facebook 预定帖子和 Twitter

oracle基本操作和查锁

使用 PHP 获取我最新的 Twitter 帖子