Отношения с базой данных или дизайн таблицы друзей для сайта социальной сети - PullRequest
6 голосов
/ 30 августа 2010

Здравствуйте, я нахожусь в процессе создания сайта социальной сети, и я хотел бы знать, как бы я хотел создать отношения между пользователями. Многие сайты говорят, что я должен создать таблицу отношений / друзей, но я смотрю в будущее и считаю, что это будет неэффективно. Эта идея может быть так же популярна, как Facebook, и я хочу быть готовым для такого количества пользователей. У Facebook 400 миллионов пользователей, поэтому таблица друзей будет как минимум в 150 раз больше. Я думаю, что выполнение запроса для друзей будет очень медленным. Таким образом, решением будет отдельная таблица для каждого пользователя, содержащая идентификаторы их друзей. или связанный файл CSV, содержащий идентификаторы. Любая помощь будет принята с благодарностью за дизайн моего сайта. Спасибо

Ответы [ 7 ]

32 голосов
/ 30 августа 2010

Создайте необходимую схему сегодня , а не ту, которая, по вашему мнению, понадобится вам через 5 лет.

Как вы думаете, Facebook разработал их схему дляподдержка 400 миллионов пользователей в первый день?Конечно, нет.Создание такого масштаба является сложным, дорогостоящим и, честно говоря, если вы попробуете сейчас, вы, вероятно, ошибетесь и в любом случае придется повторить его позже.

И давайте будем честными: у вас есть лучшешансы выиграть в лотерею, чем поражение 400 миллионов пользователей в ближайшее время.Даже если вы это сделаете, к тому времени в вашем проекте будут сотни инженеров - достаточно пропускной способности для перепроектирования вашей схемы.

Сейчас самое время создать простую.

Редактировать добавить несколько убедительных примеров:

Youtube :

Они прошли общую эволюцию: один сервер, один мастер с несколькими ведомыми считывающими устройствами, затемсекционировал базу данных, а затем остановился на подходе шардинга.

Не усложняйте!Простота позволяет вам быстрее перестроить архитектуру, чтобы вы могли реагировать на проблемы.Это правда, что никто на самом деле не знает, что такое простота, но если вы не боитесь вносить изменения, это хороший признак простоты.

Livejournal также вырос из одной базы данных на одном сервере до несколько дублированных реплицированных баз данных

Я уверен, что вы можете найти еще дюжину примеров в блоге о масштабируемости

7 голосов
/ 30 августа 2010

В то время как вы думаете о том, чтобы в конечном итоге поддержать миллионы пользователей, вы только когда-либо видели список друзей определенных людей - это ограничивает фактический объем данных существенно ...

Чтобы поддерживать нормализованные отношения дружбы в базе данных, вам понадобятся две таблицы:

ПОЛЬЗОВАТЕЛИ

  • user_id (первичный ключ)
  • имя пользователя

ДРУЗЬЯ

  • user_id (первичный ключ, внешний ключ для USERS (user_id))
  • friend_id (первичный ключ, внешний ключ для USERS (user_id))

Это остановит дублирование (IE: 1, 2), но не остановит сторнирование, потому что (2, 1) допустимо. Вам понадобится триггер, чтобы убедиться, что существует только один экземпляр отношения ...

5 голосов
/ 30 августа 2010

В вашем коде при вставке отношений в таблицу следуйте соглашению.

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

Аналогично для поиска. Конечно, это можно сделать в хранимой процедуре.

4 голосов
/ 30 августа 2010

Обе предложенные вами альтернативы, несомненно, приведут к печали - представьте, 400 миллионов таблиц или управление 400 миллионами файлов.

Определенно лучше всего поддерживать правильно проиндексированную таблицу отношений.

3 голосов
/ 30 августа 2010

Если вы ожидаете уровня успеха, достигнутого Facebook (мне нравится ваша уверенность), вы скоро поймете, что они поняли.Реляционные базы данных начинают терпеть неудачу, и вам захочется взглянуть на NoSQL решения.

При этом зачем предварительно оптимизировать работу для 400 миллионов пользователей?Создайте систему, которая будет работать, скажем, для 500 000 пользователей.Если после этого вам потребуется редизайн, вы должны быть очень успешны и располагать ресурсами для этого.

2 голосов
/ 30 августа 2010

что-то вроде этого должно сделать изначально: 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 !!
0 голосов
/ 30 августа 2010

Вы можете сделать это, используя таблицу для представления "Отношений", которые один пользователь имеет с другим пользователем. По сути, это таблица JOIN между двумя разными строками в одной таблице. Пример таблицы соединения может включать следующие столбцы:

  • USER_1_ID
  • USER_2_ID

Чтобы получить список друзей напишите запрос , который выполняет ВНУТРЕННЕЕ СОЕДИНЕНИЕ от рассматриваемого ПОЛЬЗОВАТЕЛЯ к таблице RELATIONSHIP обратно ко второму экземпляру в таблице ПОЛЬЗОВАТЕЛЬ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...