Я строю социальный граф для своего веб-сайта. Пользователи будут создавать отношения (в форме подписчик / подписчик), в которых каждая сторона может независимо следовать за другой. Моя таблица пользователей выглядит следующим образом:
Users table
- UserId (PK, Auto-incrementing integer)
Думая о том, как это смоделировать, я придумал несколько альтернатив, таких как:
(a) Таблица содержит каждое действие «следовать» в виде отдельной строки.
Relationships table
- FollowerId (FK to Users.UserId)
- FollowedId (FK to Users.UserId)
Недостаток этого метода в том, что при большом количестве пользователей будет создано огромное количество строк.
(b) Таблица содержит список пользователей, за которыми следит каждый пользователь, в виде CSV или другой структуры:
Relationships table
- FollowerId (FK to Users.UserId)
- FollowingUsers (e.g. 2,488,28,40)
Недостатком этого является то, что запросы будут намного сложнее (и дороже?). Мне также пришлось бы поддерживать порядок строковых значений и т. д.
(c) Отношение на строку, где пользователь может находиться на любой «стороне» отношения:
Relationships table
- Party1Id (FK to Users.UserId)
- FollowingParty2 (boolean)
- Party2Id (FK to Users.UserId)
- FollowingParty1 (boolean)
Это сохраняет строки более ( а), но запросы более сложны, поскольку пользователь может быть любой из сторон.
(d) Размещение как «следующих», так и «следующих» в виде списков, как (b)
Relationships table
- UserId (FK to Users.UserId)
- FollowingUsers (e.g. 2,488,28,40)
- FollowedBy (e.g. 2,488,28,40)
Это кажется лучшим из всех миров, но теперь мне приходится использовать транзакции для обновления нескольких строк.
Предположим, что я хочу масштабироваться до большого размера, хотя и знаю, что «проблемы Facebook — не мои проблемы». Какой вариант или какой другой вариант предпочтительнее?