D

Database 101: How social media “likes” are stored in a database

2025-05-27

数据库 101:社交媒体“点赞”如何存储在数据库中

你有没有想过,Instagram、Twitter、Facebook 或其他社交媒体平台是如何追踪你的帖子被点赞的?让我们在这篇文章里找到答案!

如果您刚开始接触数据库,不妨先阅读我的首篇文章《数据库入门:数据一致性入门》。这篇文章记录了我对数据库范式的探索,我的视野远远超出了之前只使用 SQL 和 MySQL 的经验。我会持续关注这个《数据库入门》系列的学习进展。

目录

1. 序言

最近,我受邀在一个名为“CityJS”的活动上发言。不过,我是个 PHP 粉,根本不会用 JS,但我接受了这个挑战。为了成功,我需要找到一个好的例子来展示一个高可扩展、低延迟的数据库是如何工作的。

于是,我向一位同事请教了一些例子。他告诉我,在任何平台中寻找高数值,比如计数器之类的。这时我意识到,任何类型的指标都可以用这个例子来表示。点赞、浏览量、评论、关注等等都可以作为计数器来查询。在本文中,你将看到我关于如何使用ScyllaDB 为这些指标进行正确数据建模的研究。

2. 让我们研究一下

总得先说最重要的事吧?决定了演讲内容之后,我需要了解如何构建这个数据模型。

我们需要一个posts表,以及一个post_likes关联每篇帖子点赞用户的表。到目前为止,这似乎足以完成我们的点赞计数器了。

我第一次尝试查询来统计所有喜欢的内容是这样的:

好的,如果我只进行查询,SELECT count(*) FROM social.post_likes它就可以工作,对吗?

嗯,它确实能用,但当我测试一篇帖子有几千个赞的时候,性能不如预期。随着赞数的增加,查询速度变得越来越慢……

“但是 ScyllaDB 可以轻松处理数千行数据……为什么它的性能不够好?”这可能就是你现在的想法(也可能不是)。

ScyllaDB —— 即使是一个功能强大的数据库,也无法解决糟糕的数据建模问题。我们需要考虑如何让速度更快。

3. 研究数据类型

好吧,让我们理清思路:我们需要存储数据,并且需要了解点赞用户之间的关系,但不能用它来计数。那么,如果我像表格integer中那样新建一行posts,然后每次都增加/减少它呢?

嗯,这似乎是个好主意,但有一个问题:我们需要跟踪帖子表上的每一个变化,如果我们开始在那里插入或更新数据,我们可能会在数据库中创建一堆无意义的记录。

使用 ScyllaDB,每次您需要更新某些内容时,您实际上都会创建新数据。

scylla@cqlsh:socials> INSERT INTO socials.posts (id, user_id, description, image_url, created_at, likes) VALUES (4d18bb8c-9c57-44fe-827a-4a2d65f331e5, 3edd5f1d-67e9-4a3e-af1a-9adbb41e2129, 'Such a cool event P99 Conf!', 'https://i.imgur.com/Xp8gi7t.jpg', '2023-04-23 15:02:49', 1);

scylla@cqlsh:socials> INSERT INTO socials.posts (id, user_id, description, image_url, created_at, likes) VALUES (4d18bb8c-9c57-44fe-827a-4a2d65f331e5, 3edd5f1d-67e9-4a3e-af1a-9adbb41e2129, 'Such a cool event P99 Conf!', 'https://i.imgur.com/Xp8gi7t.jpg', '2023-04-23 15:02:50', 2);

scylla@cqlsh:socials> INSERT INTO socials.posts (id, user_id, description, image_url, created_at, likes) VALUES (4d18bb8c-9c57-44fe-827a-4a2d65f331e5, 3edd5f1d-67e9-4a3e-af1a-9adbb41e2129, 'Such a cool event P99 Conf!', 'https://i.imgur.com/Xp8gi7t.jpg', '2023-04-23 15:02:51', 3);
Enter fullscreen mode Exit fullscreen mode
scylla@cqlsh:socials> SELECT * from posts;

 id                                 | user_id                           | created_at                    | description               | image_url                     | likes
--------------------------------------+--------------------------------------+---------------------------------+-----------------------------+---------------------------------+-------
 4d18bb8c-9c57-44fe-827a-4a2d65f331e5 | 3edd5f1d-67e9-4a3e-af1a-9adbb41e2129 | 2023-04-23 15:02:48.000000+0000 | Such a cool event P99 Conf! | https://i.imgur.com/Xp8gi7t.jpg |    1
 4d18bb8c-9c57-44fe-827a-4a2d65f331e5 | 3edd5f1d-67e9-4a3e-af1a-9adbb41e2129 | 2023-04-23 15:02:50.000000+0000 | Such a cool event P99 Conf! | https://i.imgur.com/Xp8gi7t.jpg |    2
 4d18bb8c-9c57-44fe-827a-4a2d65f331e5 | 3edd5f1d-67e9-4a3e-af1a-9adbb41e2129 | 2023-04-23 15:02:51.000000+0000 | Such a cool event P99 Conf! | https://i.imgur.com/Xp8gi7t.jpg |    3
Enter fullscreen mode Exit fullscreen mode

你必须追踪数据中所有的变化。所以,每次增加,都会多出一行,除非你不修改聚类键,或者根本不关心时间戳(这真是个愚蠢的想法)。

之后,我进入了ScyllaDB 文档,发现有一种类型counter符合我们的需求,而且也是ATOMIC 的

好吧,它符合我们的需求,但不符合我们的数据建模。要使用这种类型,我们必须遵循一些规则,但让我们先集中讨论一下目前给我们带来麻烦的那些规则:

  • 具有计数器列的表中的唯一其他列可以是主键列(无法更新)。
  • 不能包含其他类型的列。
  • 您需要使用 UPDATE 查询来处理拥有计数器数据类型的表。
  • 您只能增加或减少值,不允许设置特定值。

此限制不允许在同一操作中执行计数器和非计数器更新,从而确保正确处理计数器和非计数器更新。

因此,我们可以使用这个计数器,但不能在帖子表上使用...好的,看来我们正在寻找一种方法来完成它。

4. 正确建模

由于该counter类型不应与表中的其他数据类型“混合”,因此我们唯一的选择就是创建一个新表并存储这种类型的数据。

因此,我创建了一个名为 的新表post_analytics,它只用于存储类型。由于我们已经创建了多对多关系 (post_likes),counter因此暂时只处理“点赞” 。

对于我们创建的这个示例,您可能会运行以下查询:

## Social when you like a post

UPDATE socials.post_analytics SET likes = likes + 1 WHERE post_id = 4d18bb8c-9c57-44fe-827a-4a2d65f331e5;

INSERT INTO socials.post_likes (post_id, user_id, liked_at) VALUES (4d18bb8c-9c57-44fe-827a-4a2d65f331e5, 3edd5f1d-67e9-4a3e-af1a-9adbb41e2129, '2023-04-23 15:02:50');

# Social when you dislike a post

DELETE FROM socials.post_likes WHERE post_id = 4d18bb8c-9c57-44fe-827a-4a2d65f331e5 AND user_id = 3edd5f1d-67e9-4a3e-af1a-9adbb41e2129;

UPDATE socials.post_analytics SET likes = likes - 1 WHERE post_id = 4d18bb8c-9c57-44fe-827a-4a2d65f331e5;
Enter fullscreen mode Exit fullscreen mode

现在,你可能会有新的疑问,比如:“所以每次我需要一个与某些数据相关的新计数器时,我都需要一个新表吗?”嗯,这取决于你的用例。在社交媒体的案例中,如果你想存储谁看过帖子,你可能需要一个post_viewers包含 session_id 和其他一些信息的表。

这些无需连接即可完成的简单查询比查询要快得多count(*)

5. 最后的考虑

我在 CityJS 舞台上演讲

我在 CityJS 阶段说了一堆使用 TS 进行数据建模的废话

我学到了很多东西,不仅通过学习新的数据建模方法,而且还学习了 TypeScript 来创建 CityJS 演示文稿并构建这个用例。

由于一切对我来说都是全新的,我会尽力继续分享我的学习成果。欢迎在评论区指正!讨论是学习新事物的最佳途径。

别忘了点赞这篇文章、在社交媒体上关注我,然后装满你的水瓶 xD

Twitter DanielHe4rt PT-BR
Twitter DanielHe4rt EN
Twitch 频道

文章来源:https://dev.to/scylladb/database-101-how-social-media-likes-are-stored-in-a-database-3oii
PREV
10 个优秀的编程项目,助你提升简历,学习编程 wemake-python-styleguide
NEXT
自述文件模板 如何编写出色的自述文件