如何为“入住”社会服务设计数据库

时间:2014-06-08 19:07:08

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

我希望建立“{3}}或FourSquare等”登记“服务。

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

例如,假设我正在开发“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          |
+-----+------+---------------+----------------+

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

例如,我想记录安妮已经办理了多少法国奶酪。鲍勃已经检查了哪些奶酪等。如果Cersei吃过卡门培尔奶酪超过5次等。

我最好把这些信息放在用户的桌子上吗? E.g。

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

看起来相当笨拙且难以维持。那么我应该有单独的录音登记表吗?

3 个答案:

答案 0 :(得分:1)

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

连接表(我们称之为cheeses_users)必须至少有两列(user_ID, cheese_ID),但第三列(时间戳)也是有用的。如果将timestamp列默认为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

答案 1 :(得分:1)

让我们更清楚地定义,所以你可以告诉我我是不是错了:

  • 奶酪实例存在且不可分割(“Cheddar / UK / Traditional / Yellow”是有效的可检查奶酪,但“Cheddar”不是,也不是“黄色”或“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            |
+-----+------------+--------------+

这会大大减少你的加入表的大小,虽然显然没有“纸质记录”,如果你需要重建你的数据(并且可能对用户说“哦,是的,我们忘记记录你的签到在这样的日期。“)

答案 2 :(得分:0)

实体'User'和'Cheese'具有多对多关系。用户可以检查多个奶酪,奶酪可以有多个人检查。

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

你的表应该是这样的:

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

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