你有没有想过 Instagram、Twitter、Facebook 或任何社交媒体平台如何跟踪谁喜欢你的帖子?让我们在这篇文章中弄清楚!
1:序言
最近,我受邀在一个名为“CityJS”的活动中发言。但问题在于:我是 PHP 开发人员。我根本不懂JS,但我接受了挑战。为了成功,我需要找到一个很好的例子来展示高度可扩展和低延迟的数据库是如何工作的。
于是,我向我的一位同事寻求了例子。他告诉我要在任何平台上寻找高数字,例如计数器之类的东西。在那一刻,我意识到任何类型的度量标准都可以适用于这个例子。例如,点赞数、浏览量、评论数、关注数等都可以被查询为计数器。在这篇文章中,您将找到我对如何使用ScyllaDB进行适当的数据建模的研究。
2:让我们研究一下
要事第一,对吧?在决定了我的演讲要涵盖的内容之后,我需要了解如何构建此数据模型。
我们需要一个posts
表格,还有一个post_likes
表格来关联每个帖子的点赞者。到目前为止,似乎足以计算我们的喜好。
我第一次打赌计算所有喜欢的查询是这样的:
“好吧,如果我只是用SELECT count(*) FROM social.post_likes
它做一个查询就可以了,对吧?”
好吧,它确实有效,但是当我在一篇文章中对几千个赞进行测试时,它的性能不如预期。随着点赞数的增加,查询变得越来越慢......
“但是 ScyllaDB 可以轻松处理数千行……为什么它的性能不佳?” 这可能就是您现在(或可能不是)的想法。
ScyllaDB——即使作为一个具有很酷功能的很酷的数据库——也不会解决糟糕的数据建模问题。我们需要考虑如何让事情变得更快。
3:研究数据类型
好的,让我们直接思考:数据需要存储,我们需要谁喜欢我们的帖子之间的关系,但我们不能用它来计数。那么,如果我integer
在posts
表中创建一个新行并每次递增/递减它呢?
好吧,这似乎是个好主意,但有一个问题:我们需要跟踪 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);
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
您将必须跟踪数据中发生的所有变化。因此,每次增加,都会多一行,除非您不更改集群键或不关心时间戳(一个非常愚蠢的想法)。
在那之后,我进入了ScyllaDB 文档,发现有一种类型叫做counter
满足我们的需要并且也是ATOMIC!
好的,它符合我们的需求但不符合我们的数据建模。要使用这种类型,我们必须遵循一些规则,但让我们关注那些现在给我们带来麻烦的规则:
在具有计数器列的表中,唯一允许的其他列是主键列(不能更新)。
不允许包含任何其他类型的列。
必须使用 UPDATE 查询处理拥有计数器数据类型的表。
你只能增加或减少值,不能设置特定的值。
通过不允许在同一操作中处理计数器和非计数器更新,此限制确保了对计数器和非计数器更新的正确处理。
所以,我们可以使用这个计数器,但不能用在 posts 表上……好吧,看来我们正在寻找一种方法来完成它。
4:正确建模
counter
有了类型不应与表中的其他数据类型“混合”的信息,留给我们的唯一选择是创建一个新表并存储这种类型的数据。
所以,我创建了一个名为的新表post_analytics
,它只包含counter
类型。目前,让我们只处理喜欢,因为我们已经创建了多对多关系 (post_likes)。
这些接下来的查询是您可能会为我们创建的这个示例运行的查询:
## 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;
现在你可能会有新的未解决问题,比如:“那么每次我需要一个与某些数据相关的新计数器,我都需要一个新的表吗?”好吧,这取决于你的用例。在社交媒体的情况下,如果你想要存储谁看过这篇文章,你可能需要一个post_viewers表,其中包含session_id和一些其他内容。
使用这些可以在不需要连接的情况下完成的简单查询可能比使用count(*)查询更快。
作者:Daniel Reis
更多技术干货、热门资讯请关注公号“云原生数据库”