社交网站的数据库关系或朋友表设计

时间:2010-08-30 17:28:05

标签: php mysql database database-design

您好我正在创建一个社交网站,我想知道如何创建用户之间的关系。许多网站都说我应该创建一个关系/朋友表,但我展望未来并相信这将是无效的。这个想法可能像Facebook一样受欢迎,我想为那么多用户做好准备。 Facebook有4亿用户,所以朋友表至少是其中的150倍。我想,对一些朋友进行查询会很慢。那么解决方案是否是包含其朋友ID的每个用户的单独表格。或包含ID的关联CSV文件。任何帮助将非常感谢我的网站的设计。感谢

7 个答案:

答案 0 :(得分:32)

构建您今天所需的架构 ,而不是您认为5年后需要的架构。

你认为facebook在第一天设计了他们的架构以支持4亿用户吗?当然不是。建造这种规模是复杂,昂贵,而且老实说,如果你现在尝试,你可能会弄错它,无论如何都必须重做它。

说实话:你有更好的机会赢得彩票,而不是很快就会有4亿用户。即使你这样做,你的项目也会有数百名工程师 - 为重新设计你的架构提供足够的带宽。

现在是构建简单的时候了。

修改以添加一些可靠的示例:

Youtube

  

他们经历了一个共同的演变:   单个服务器,去了一个主人   然后,有多个读取从属   分区数据库,然后   坚定不移的方法。

     

保持简单!简单性让你   尽快重新架构,以便你可以   回应问题。这是真的   没人知道简单   是的,但如果你不害怕   然后改变那是一个好兆头   简单性正在发生。

Livejournal也从单个服务器上的单个数据库发展到multiple sharded replicated databases

我相信你可以在the highscalability blog

上找到更多的例子

答案 1 :(得分:7)

虽然您认为最终会支持数百万用户,但您只会看到特定的人物朋友列表 - 这实际上限制了的实际数据 ...

为了在数据库中维护规范化的友谊关系,您需要两个表:

用户

  • user_id(主键)
  • 用户名

FRIENDS

  • user_id(主键,USERS的外键(user_id))
  • friend_id(主键,USERS的外键(user_id))

这将阻止重复(IE:1,2)发生,但不会因为(2,1)有效而停止反转。您需要一个触发器来强制执行只有一个关系实例...

答案 2 :(得分:5)

在代码中,将关系插入表时,请遵循约定。

issueSQLQuery("INSERT INTO relationships (friend1, friend2) 
    VALUES (?, ?)", min(friend_1_ID, friend_2_ID), max(friend_1_ID, friend_2_ID))

同样也可以进行检索。当然,这可以在存储过程中完成。

答案 3 :(得分:4)

你提出的两种选择无疑会导致悲痛 - 想象4亿张牌桌,或管理4亿张文件。

绝对最好维护正确索引的关系表。

答案 4 :(得分:3)

如果你期望Facebook获得成功的水平(我喜欢你的信心),你很快就会意识到他们意识到了什么。关系数据库开始不足,你需要研究NoSQL解决方案。

话虽如此,为什么要为4亿用户预先优化?建立一个现在可以为500,000个用户工作的系统。如果你需要在那之后重新设计,那么你必须非常成功,并且有资源这样做。

答案 5 :(得分:2)

这样的事情应该是你最初做的:http://pastie.org/1127206

drop table if exists user_friends;
drop table if exists users;

create table users
(
user_id int unsigned not null auto_increment primary key,
username varchar(32) unique not null,
created_date datetime not null
)
engine=innodb;

delimiter #

create trigger users_before_ins_trig before insert on users
for each row
begin
 set new.created_date = now();
end#

delimiter ;

create table user_friends
(
user_id int unsigned not null,
friend_user_id int unsigned not null,
created_date datetime not null,
primary key (user_id, friend_user_id), -- note clustered composite PK
foreign key (user_id) references users(user_id),
foreign key (friend_user_id) references users(user_id)
)
engine=innodb;

delimiter #

create trigger user_friends_before_ins_trig before insert on user_friends
for each row
begin
 set new.created_date = now();
end#

delimiter ;


drop procedure if exists insert_user;

delimiter #

create procedure insert_user
(
in p_username varchar(32)
)
proc_main:begin

  insert into users (username) values (p_username);

end proc_main #

delimiter ;

drop procedure if exists insert_user_friend;

delimiter #

create procedure insert_user_friend
(
in p_user_id int unsigned,
in p_friend_user_id int unsigned
)
proc_main:begin

  if p_user_id = p_friend_user_id then
    leave proc_main;
  end if;

  insert into user_friends (user_id, friend_user_id) values (p_user_id, p_friend_user_id);

end proc_main #

delimiter ;

drop procedure if exists list_user_friends;

delimiter #

create procedure list_user_friends
(
in p_user_id int unsigned
)
proc_main:begin

  select
    u.*
  from
    user_friends uf
  inner join users u on uf.friend_user_id = u.user_id
  where
    uf.user_id = p_user_id
  order by
   u.username;

end proc_main #

delimiter ;

call insert_user('f00');
call insert_user('bar');
call insert_user('bish');
call insert_user('bash');
call insert_user('bosh');

select * from users;

call insert_user_friend(1,2);
call insert_user_friend(1,3);
call insert_user_friend(1,4);
call insert_user_friend(1,1); -- oops

call insert_user_friend(2,1);
call insert_user_friend(2,5);

select * from user_friends;

call list_user_friends(1);
call list_user_friends(2);

-- call these stored procs from your php !!

答案 6 :(得分:0)

您可以使用表来表示一个用户与另一个用户的“关系”。这实际上是同一个表中两个不同行之间的JOIN表。示例连接表可能包含以下列:

  • USER_1_ID
  • USER_2_ID

获取从有问题的USER执行INNER JOIN到RELATIONSHIP表的朋友列表write a query回到USER表上的第二个实例。