【问题标题】:Efficient MySQL database design for a Tinder like app为类似 Tinder 的应用程序设计的高效 MySQL 数据库
【发布时间】:2019-03-11 13:57:54
【问题描述】:

我正在创建一个像 Tinder 这样的应用程序。用户可以向右滑动或喜欢,向左滑动或不喜欢其他用户。问题是关于存储用户的操作。如下用户操作需要一个表

Person 1.   |   Person 2.    |     op
__________________________________
000001.          000007.          Dislike
000001.          000011.          Like
000001.          000053.          Dislike
000001.          000173.          Dislike

它存储操作,也用于不向用户显示更多次。到现在还好。

但问题是,如果只有 1000 个用户刷另外 1000 个用户,该表将有 1M 行。如果有 100,000 个用户这样做......它会达到 100M 行!这是非常巨大的。

你们有什么想法不要让结构设计变得这么大吗?

谢谢。

【问题讨论】:

  • 此外,现代数据库系统的设计目的是在可以使用索引的情况下处理数百万甚至数十亿条记录,如果确实需要,您还可以在此基础上部署分区。
  • 像这样在(薄)表中存储 100M 行不是问题。根据您要选择的内容和方式,从中检索 sumerized 数据可能是个问题。在这种情况下,您可能需要一个触发器管理的临时表,它将保存关系的当前状态(每个关系一行)。
  • 是的,但这不仅仅是关于数据库。即使 MySQL 可以处理数百万行,它也需要大量的 RAM 和 CPU。你知道我不是硅谷公司吗? ;) 我正在考虑一个解决方案......我们向用户显示用户队列。如果我们设置一个指针,告诉用户刷到队列中的第 37 位用户(例如)并存储喜欢的用户怎么办?然后,如果喜欢的用户不喜欢第一个用户,我们会删除该行。你觉得怎么样?
  • “是的,但不仅仅是数据库。即使 MySQL 可以处理数百万行,它也需要大量的 RAM 和 CPU。” 表结构是什么? SHOW CREATE TABLE table 也许您应该规范化列以保存 INTBIGINT 而不是 VARCHAR 以节省 RAM/磁盘空间。此外,数据库很可能是更多的磁盘 I/O 限制然后 CPU 限制
  • 按照@ArnaudPeralta 的建议去做,让用户在那里选择性取向,并在创建帐户时添加更多过滤器,如年龄、国家、状态。并使用过滤器仅向用户显示匹配的其他用户帐户那些过滤器。

标签: mysql database data-structures tinder


【解决方案1】:

有几件事需要考虑。

首先,除非您知道需要运行的查询类型,否则表的大小并不是很有趣。正如其他人所说,具有数亿行的表没什么好怕的,如果您要查询可索引字段,您可能可以扩展到 数十亿 行,而无需使用奇异的解决方案通过购买更大更好的硬件。因此,90% 的查询都是

select * from users where user_id not in (select interacted_user_id from interactions where interacting_user_id = $current_user) limit 10

我的猜测是,这将在您的笔记本电脑上扩展到数亿行,在体面的服务器上扩展到数十亿行。我的强烈建议是使用简单的关系解决方案,而不使用分区或其他奇特的解决方案,直到您扩展到不再起作用的程度,并且您已经调整了查询​​并尽可能升级了您的硬件。这比任何其他解决方案更便宜/更容易。

更大的挑战将是地理空间方面 - 大概,您希望根据与当前用户的距离对结果进行排序。

您可以对数据进行分区的一种方法是按区域收集“交互”。这需要一些思考 - 你可能不想要“硬”边界,而是有重叠的地理区域。地图上的每个点都可能有几个重叠的“区域”,每个区域都有自己的表格。您在一个区域中拥有的用户越多,重叠的圆圈就越小 - 曼哈顿可能有 3 个区域,格陵兰可能只有 1 个。然后您的查询会查看每个重叠区域的表,并将以前没有的用户联合起来与当前用户交互。

【讨论】:

    【解决方案2】:

    如果人 1 不喜欢人 2,则无需将人 1 显示给人 2。即使您显示他,他们也永远不会匹配。因此,您的计算 1K x 1K = 1M 有点高估了。

    但是,如果您仍然想为两个用户设置喜欢/不喜欢的集合,您可能会考虑“压缩”行这种糟糕的想法。

    想象一下你有一个这样的序列:

    | Person 1 | Person 2 |  Op       |
    | -------- | -------- | --------- |
    | 0001     | 1010     |  Dislike  |
    | 0001     | 1011     |  Dislike  |
    | 0001     | 1012     |  Dislike  |
    | 0001     | 1013     |  Dislike  |
    | 0001     | 1015     |  Like     |
    | 0001     | 1017     |  Dislike  |
    | 0001     | 1018     |  Dislike  |
    | 0001     | 1019     |  Dislike  |
    | 0001     | 1021     |  Like     |
    

    如果您有 id 互相关注,您可能会将它们显示为

    | Person 1 | Person 2 |  Op       | N    |
    | -------- | -------- | --------- | ---- |
    | 0001     | 1010     |  Dislike  | 3    |
    | 0001     | 1015     |  Like     | 0    |
    | 0001     | 1017     |  Dislike  | 2    |
    | 0001     | 1021     |  Like     | 0    |
    

    其中 N 是序列中的最大 id(例如 1010 + 3 = 1013)。如果将 N 定义为 unsigned tinyint,则序列的最大可能大小可以是 255,这意味着理论上可以将 255 个连续的不喜欢/喜欢保存为 1 条记录。

    查询将是这样的(假设您正在寻找 id 1013):

    SELECT a.* 
    FROM (
        SELECT *
        FROM `table`
        WHERE person_1 = 0001
          AND person_2 >= (1013 - 255) -- 255 is a max size of a sequense 
          AND person_2 <= 1013
    ) a
    WHERE a.person_2 <= 1013 AND a.person_2 + N >= 1013
    

    子选择将限制可能记录的范围,然后主选择将匹配该记录(如果存在)。在这种情况下,它将是

    | Person 1 | Person 2 |  Op       | N    |
    | -------- | -------- | --------- | ---- |
    | 0001     | 1010     |  Dislike  | 3    |
    

    但是,就我个人而言,我会接受这个并更喜欢您当前的解决方案,因为它很简单。

    或 作为另一种变体,您可以通过这种方式压缩表格

    | Person 1 | Person 2 | Max Person 2 |  Op       |
    | -------- | -------- | ------------ | --------- |
    | 0001     | 1010     | 1013         |  Dislike  |
    | 0001     | 1015     | 1015         |  Like     |
    | 0001     | 1017     | 1019         |  Dislike  |
    | 0001     | 1021     | 1021         |  Like     |
    

    【讨论】:

    • 有点过度设计,但在数据库空间成为问题的地方很有意义。尤其是第二种变体,更容易推理。
    【解决方案3】:

    你永远不会有 100 万行,因为如果你在做一个类似 Tinder 的应用程序,你可以重新匹配人。所以我建议你添加一个日期列来知道你什么时候可以删除行和存储过程,你可以执行它来清理过期的关系。

    使用此列,行不会堆叠,您将永远不会有数百万行。

    另外,当人们喜欢在一起时,您也不需要存储。

    编辑:为什么不使用两列 CHECKSUM() 来存储每个关系的哈希?它会更轻。

    EDIT2:别忘了这是一个爱情应用。而且人们并不适合所有人,因为他们有性取向。

    【讨论】:

    • 操作永不过期。因为如果用户 A 喜欢或不喜欢用户 B,则用户 B 不能再次显示给用户 A。该表也用于此目的。
    • 所以对我来说,你能做的最好的事情就是当你更新你的表时要小心,因为当已经有一个 B | A | dislike 时不要更新 A | B | dislike。如果第二个人在第一个人也点了赞,则删除一行。
    • "for not update A | B | dislike when has a B | A | dislike" topicstarter表是源目标表..如果A不喜欢人B 为什么不可能 B 也不喜欢 A?或者像这件事一样。
    • 如果有人不喜欢一个人,为什么这个人会有这个人的建议?没用的。所以无论如何它都保存了 1 行。
    • 因为只是在现实生活中一个人可以不喜欢一个人,但不喜欢的人仍然可以喜欢不喜欢他/她的人.. 这也接缝了 topicstarters 点..
    猜你喜欢
    • 2010-12-19
    • 1970-01-01
    • 2013-09-25
    • 1970-01-01
    • 2019-10-21
    • 2011-09-22
    • 2011-12-21
    • 2014-02-07
    • 2013-12-31
    相关资源
    最近更新 更多