社交网络中 activity 流的数据库架构和查询

Database schema and queries for activity stream in social network

首先,我不是 DBA 或 SQL 专家。但是我接手了一个个人项目,该项目要求我全权负责建立社交网络。 (不,我不是要重塑 Facebook。我的目标是小众受众。)是的,我听说过 http://activitystrea.ms/ 等框架,但我觉得数据序列化应该是我的需求。

无论如何,How to implement the activity stream in a social network 帮助我开始工作,但我还有一些未解决的问题。

下面是我的数据库架构(为了简化省略了一些行):

动作table:

id    name
-------------
1     post
2     like
3     follow
4     favorite
5     tag
6     share

Activity table:

id             (int)
user_id        (int)
action_id      (tinyint)
target_id      (int)
object_id      (tinyint)
date_created   (datetime)

object_id指的是target_id是哪种对象类型。这里的思路是表示(User + Action + Target Object)

对象(类型)table:

id    name
-------------
1     media
2     scene
3     brand
4     event
5     user

这里的问题是每个 object 都有自己独立的 table。例如:

媒体table:

id            (int)
type          (int)
thumbnail     (varchar)
source        (varchar)
description   (varchar)

事件table:

id        (int)
user_id   (int)
name      (varchar)
city      (int)
address   (varchar)
starts    (time)
ends      (time)
about     (varchar)

用户table:

id                (int)
username          (varchar)
profile_picture   (varchar)
location          (int)

那么,查询此数据库的最佳(即最有效)方式是什么?

显然我可以在 activity table 上执行 SELECT 语句,然后 – 基于 object_id – 在 PHP 中使用条件逻辑对适当的 object 的 table(例如 media)进行单独查询。

或者在所有 5 object table 上实现某种左或内 JOIN 会更聪明(也更有效),如这里所建议的:MySQL if statement conditional join.我并不完全熟悉 JOINS 的工作原理,以及 SQL 是否足够聪明,只为每个 activity 行扫描适当的 object table,而不是比所有加入的 tables.

当然,第一个解决方案意味着对数据库的调用更多,这是不太理想的。但是,我不确定在不实现某些条件逻辑的情况下如何仅在一个查询中检索所有相关列(例如 media "source"、event "address") .

假设,您将 activity table 稍微改变一下:

Activity table:

id             (int)
user_id        (int)
action_id      (tinyint)
object_id      (tinyint)
date_created   (datetime)

和您的加入 table 每个目标类型:

activity_id    (int)
target_id      (int)

最后是你的目标 table(媒体)

id            (int)
type          (int)
thumbnail     (varchar)
source        (varchar)
description   (varchar)

和目标 table(事件)

id        (int)
user_id   (int)
name      (varchar)
city      (int)
address   (varchar)
starts    (time)
ends      (time)
about     (varchar)

现在,您可以 select 数据

SELECT
 activity.id,
 activity.user_id,
 activity.action_id,
 action.name,
 activity.object_id,
 object.name,
 media.id as media_id,
 media.type,
 media.thumbnail,
 media.source,
 media.description,
 event.id as event_id,
 event.name,
 ...
FROM
 activity
 LEFT JOIN action ON (action.id = activity.action_id)
 INNER JOIN mediaToActivity ON (mediaToActivity.activity_id = activity.id)
 LEFT JOIN media ON (media.id = mediaToActivity.target_id)
 INNER JOIN eventToActivity ON (eventToActivity.activity_id = activity.id)
 LEFT JOIN event ON (event.id = eventToActivity.target_id)

使用此查询,您应该在一个查询中获取所有行(但只有实际存在的行才会填充数据)

请注意,我现在还没有测试过...

我从您的讨论中拼凑出您的解决方案。 Fiddle

create table activity (
  id            int,   
  user_id       int,
  action_id     int,
  target_id     int,
  object_id     int,
  date_created  datetime
);
create table action (
  id int,
  name varchar(80)
);
create table object (
  id int,
  name varchar(80)
);
create table media (
  id int,
  type int,
  thumbnail varchar(255),
  source varchar(255),
  description varchar(255)
);
create table event (
  id       int,
  user_id   int,
  name      varchar(255),
  city      int,
  address   varchar(255),
  starts    time,
  ends      time,
  about     varchar(255)
);

-- setup
insert into action values (1, "post");
insert into object values (1, "media");
insert into object values (2, "event");

-- new event
insert into event values (1, null, "breakfast", null, "123 main st", null, null, "we will eat");
insert into activity values (1, null, 1, 1, 2,  null);

-- new media
insert into media values (1, null, null, null, "new media");
insert into activity values (2, null, 1, 1, 1,  null);

SELECT *
FROM
 activity
 left join event on (event.id = activity.target_id and activity.object_id = 2)
 left join media on (media.id = activity.target_id and activity.object_id = 1);