【问题标题】:How To Design A Database for a "Check In" Social Service如何为“签到”社会服务设计数据库
【发布时间】:2014-06-08 19:07:08
【问题描述】:

我想构建一个“签到”服务,例如 FourSquareUntappd

如何设计一个合适的数据库架构来存储签到?

例如,假设我正在开发“CheeseSquare”来帮助人们跟踪他们尝试过的美味奶酪。

可以签入的项目表相当简单,看起来像

+----+---------+---------+-------------+--------+
| ID |  Name   | Country |    Style    | Colour |
+----+---------+---------+-------------+--------+
|  1 | Brie    | France  | Soft        | White  |
|  2 | Cheddar | UK      | Traditional | Yellow |
+----+---------+---------+-------------+--------+

我也会为用户准备一张桌子,比如说

+-----+------+---------------+----------------+
| ID  | Name | Twitter Token | Facebook Token |
+-----+------+---------------+----------------+
| 345 | Anne | qwerty        | poiuyt         |
| 678 | Bob  | asdfg         | mnbvc          |
+-----+------+---------------+----------------+

记录用户签到特定奶酪的最佳方式是什么?

例如,我想记录 Anne 签到了多少法国奶酪。鲍勃检查过哪些奶酪等。如果瑟曦吃卡门贝尔奶酪超过 5 次等等。

最好将此信息放在用户表中吗?例如

+-----+------+------+--------+------+------+---------+---------+
| ID  | Name | Blue | Yellow | Soft | Brie | Cheddar | Stilton |
+-----+------+------+--------+------+------+---------+---------+
| 345 | Anne |    1 |      0 |    2 |    1 |       0 |       5 |
| 678 | Bob  |    3 |      1 |    1 |    1 |       1 |       2 |
+-----+------+------+--------+------+------+---------+---------+

这看起来相当笨拙且难以维护。那么我应该为记录签入单独的表格吗?

【问题讨论】:

标签: mysql sql database database-design social-networking


【解决方案1】:

不,不要将其放入users 表中。该信息最好存储在表示用户和奶酪之间的多对多关系的连接表中。

连接表(我们称之为cheeses_users)必须至少有两列(user_ID, cheese_ID),但第三列(时间戳)也很有用。如果将时间戳列默认为CURRENT_TIMESTAMP,则只需将user_ID, cheese_ID插入表中即可记录签到。

cheeses (ID) ⇒ (cheese_ID) cheeses_users (user_ID) ⇐ users (ID)

创建为:

CREATE TABLE cheeses_users
  cheese_ID INT NOT NULL,
  user_ID INT NOT NULL,
  -- timestamp defaults to current time
  checkin_time DATETIME DEFAULT CURRENT_TIMESTAMP,
  -- (add any other column *specific to* this checkin (user+cheese+time))
  --The primary key is the combination of all 3
  -- It becomes impossible for the same user to log the same cheese
  -- at the same second in time...
  PRIMARY KEY (cheese_ID, user_ID, checkin_time),
  -- FOREIGN KEYs to your other tables
  FOREIGN KEY (cheese_ID) REFERENCES cheeses (ID),
  FOREIGN KEY (user_ID) REFERENCES users (ID),
) ENGINE=InnoDB; -- InnoDB is necessary for the FK's to be honored and useful

要记录 Bob & Cheddar 的签到,请插入:

INSERT INTO cheeses_users (cheese_ID, user_ID) VALUES (2, 678);

要查询它们,您可以通过此表加入。例如,要查看每个用户的每种奶酪类型的数量,您可以使用:

SELECT
  u.Name AS username,
  c.Name AS cheesename,
  COUNT(*) AS num_checkins
FROM
  users u
  JOIN cheeses_users cu ON u.ID = cu.user_ID
  JOIN cheeses c ON cu.cheese_ID = c.ID
GROUP BY
  u.Name,
  c.Name

要获取给定用户最近的 5 次签到,例如:

SELECT
  c.Name AS cheesename,
  cu.checkin_time
FROM
  cheeses_users cu
  JOIN cheeses c ON cu.cheese_ID = c.ID
WHERE 
  -- Limit to Anne's checkins...
  cu.user_ID = 345
ORDER BY checkin_time DESC
LIMIT 5

【讨论】:

    【解决方案2】:

    让我们定义得更清楚,如果我错了你可以告诉我:

    • 奶酪实例存在且不可分割(“Cheddar/UK/Traditional/Yellow”是有效的可检查奶酪,但“Cheddar”不是,“Yellow”或“Cheddar/France/...)
    • 用户在给定时间签入单个奶酪实例
    • 用户可以在以后重新签入同一个奶酪实例。

    如果是这种情况,那么要存储完全规范化的数据并能够检索该数据的历史记录,您需要连接两个现有表的第三个关系表。

    +-----+------------+---------------------+
    | uid |  cheese_id | timestamp           |
    +----+-------------+---------------------+
    | 345 | 1          | 2014-05-04 19:04:38 |
    | 345 | 2          | 2014-05-08 19:04:38 |
    | 678 | 1          | 2014-05-09 19:04:38 |
    +-----+------------+---------------------+
    

    等等。您可以添加额外的列来对应奶酪数据,但严格来说您不需要。

    通过将所有这些都放在第三张表中,您可能会提高性能和灵活性。您始终可以使用聚合查询重新构建对您提出的用户表的添加。

    如果您真的决定不需要时间戳,那么您可以将它们替换为基本上相当于 COUNT(*) 字段:

    +-----+------------+--------------+
    | uid |  cheese_id | num_checkins |
    +----+-------------+--------------+
    | 345 | 1          | 15           |
    | 345 | 2          | 3            |
    | 678 | 1          | 8            |
    +-----+------------+--------------+
    

    如果您需要重建数据(并且可能对用户说“哦,是的,我们忘记记录您的签到记录,这将大大减少您的联接表的大小,尽管显然“书面记录”更少了)在这样的日期。”)

    【讨论】:

      【解决方案3】:

      实体“用户”和“奶酪”具有多对多关系。一个用户可以签入多个奶酪,一个奶酪可以有多个人签入。

      在关系数据库中唯一正确的设计方法是将其存储到单独的表中。例如,将其存储到用户表中是一个非常糟糕的主意有很多原因。阅读规范化数据库以获取更多信息。

      您的表格应如下所示:

      CheckIns(CheeseId, UserId, (etc...))
      

      其他有用的列可能包括日期或评级,或者您想要存储的关于用户和奶酪之间特定关系的任何内容。

      【讨论】:

        猜你喜欢
        • 2018-02-27
        • 2016-12-13
        • 2010-12-26
        • 2011-03-17
        • 1970-01-01
        • 2019-08-11
        • 2021-11-17
        • 1970-01-01
        相关资源
        最近更新 更多