Так же, как обновление для Утесов, Спасибо ChaosPandion для шаблона.
Человек
Интервал PersonID PK
Сеть
Интервал PersonID PK FK
Интервал OtherPersonID PK FK
ИЛИ
Человек
Интервал PersonID PK
Сеть
Интервал PersonID PK FK
Интервал FriendID PK FK
Друг
Интервал FriendID PK
Интервал OtherPersonID FK
++++++ Исходное сообщение ниже ++++++
Привет все,
Я - веб-разработчик и недавно запустил проект с компании. В настоящее время я работаю с их DBA на получении схемы, размеченной для сайта, и мы пришли к разногласию относительно дизайна на паре таблиц, и я хотел бы некоторые мнения о вопросе.
В основном мы работаем над сайтом, который реализует "друзей" сеть. Все пользователи сайта будут содержаться в таблице tblUsers с (идентификационные данные интервала PersonID PK, и т.д.).
То, что я желаю сделать, должно составить вторую таблицу, tblNetwork, который будет содержать все отношения между пользователями, с (идентификационные данные интервала NetworkID PK, интервал Owners_PersonID FK, интервал Friends_PersonID FK, и т.д.). Или с другой стороны, удалите NetworkID и имейте и Owners_PersonID и Friends_PersonID, совместно использованный как Первичный ключ.
Это - то, где DBA имеет его проблему. При высказывании, что "он только реализовал бы этот вид архитектуры в схеме организации хранилищ данных, а не для веб-сайта, и это - просто другой пример веб-разработчиков, пытающихся вынуть простой способ".
Теперь, очевидно, его комментарий был немного подстрекательским, и которые помогли заставить меня находить подходящий ответ, но больше, я был бы точно так же, как, чтобы знать, как сделать его правильно. Я разрабатывал базы данных и программировал больше 10 лет, работал с некоторыми первоклассными умами и никогда не слышал этот вид аргумента.
То, что DBA желает сделать, вместо того, чтобы хранить и Owners_PersonId и Friends_PersonId в той же таблице, должен составить третью таблицу tblFriends для хранения Friends_PersonId, и иметь tblNetwork имеют (идентификационные данные интервала NetworkID PK, интервал Owner_PersonID FK, интервал FriendsID FK (от TBLFriends)). Все, что содержал бы tblFriends, будет (идентификационные данные интервала FriendsID PK, Friends_PersonID (связано назад с Людьми)).
Мне, составляя третью таблицу является просто чрезмерным по своей природе, и действительно только создает псевдоним для Friends_PersonID и заставляет меня должным быть добавлять (что я просматриваю как ненужное), соединяет со всеми моими запросами, не говоря уже о дополнительных циклах, которые будут необходимы для выполнения соединения на каждом запросе.
Я понимаю, что технически, то, что он желает, возможно, но это встроено с лучшей практикой? Какова была бы лучшая практика?
Спасибо за чтение цените комментарии.
Ryan
Ваш проект нарушает Третью нормальную форму , если Network.Owners_PersonID
хранится в сети с избыточностью.
Но я не понимаю, как на самом деле помогает дизайн DBA. Я ожидал, что Друзья
будут таблицей «многие-ко-многим» между пользователями
и Сетями
:
CREATE TABLE tblUsers (
PersonID INT IDENTITY PRIMARY KEY
);
CREATE TABLE tblNetworks (
NetworkID INT IDENTITY PRIMARY KEY,
Owner_PersonID INT NOT NULL REFERENCES tblUsers
);
CREATE TABLE tblFriends (
NetworkID INT NOT NULL REFERENCES tblNetworks,
FriendID INT NOT NULL REFERENCES tblUsers,
PRIMARY KEY(NetworkID, FriendID)
);
Другими словами, у вас есть простая таблица «многие-ко-многим». отношение ко многим:
Users ----<- Friends ->---- Networks
И, кроме того, Networks
ссылается на Users
только для идентификации владельца данной сети. Таким образом, для данной сети есть только одна строка, поэтому вы не можете создать аномалию обновления, изменив владельца сети в некоторых строках.
Я не думаю, что это чрезмерное разбиение сущностей на отдельные таблицы. Вы по-прежнему можете получить список друзей для данной сети:
SELECT ... FROM Networks n JOIN Friends f ON (n.NetworkID=f.NetworkID)
Таким способом можно получить всех друзей пользователя из всех сетей (передайте идентификатор данного пользователя в параметре ?
):
SELECT ... FROM Friends u
JOIN Friends f ON (u.NetworkID=f.NetworkID)
WHERE u.UserID = ?
В вашем первоначальном дизайне это почти то же самое:
SELECT ... FROM Networks u
JOIN Networks f ON (u.Owner_UserID=f.Owner_UserID)
WHERE u.FriendID = ?
Но преимущество в том, что вы устранили возможную аномалию обновления.
Я хочу создать вторую таблицу, tblNetwork, которая будет содержать все отношения между пользователями с (NetworkID int identity {{ 1}} PK, Owners_PersonID int FK, Friends_PersonID int FK и т. Д.). Или, наоборот, удалите NetworkID и укажите как Owners_PersonID, так и Friends_PersonID в качестве основного ключа .
Я не вижу в этом никаких проблем. И я согласен с тем, что NetworkID
является лишним - два FK являются естественным ключом для таблицы, и поэтому вы должны просто использовать их в качестве первичного ключа, если у вас нет причин производительности, по которым вам нужно ссылаться к конкретным отношениям по суррогатному идентификатору (которого у вас, похоже, нет в данном случае).
Я говорю, делайте это по-своему. Наличие этой третьей таблицы усложняет программирование.
Если я вас правильно понимаю, вы предлагаете:
Person PersonID PK
FriendList FriendListID, OwnerID, PersonID
DBA предлагает:
Person PersonID PK
FriendList FriendListID, OwnerID
FriendListEntry FriendListID, PersonID
Ваш подход потребует нескольких строк для каждый друг в списке. Это будет повторять OwnerID несколько раз, нарушая нормальную форму. Решение DBA более нормализовано, имея только значения, зависящие от FriendListID в таблице FriendList.
Лучшая практика здесь - быть хорошими друзьями с администратором баз данных. Я бы согласился с его решением, потому что это не имеет большого значения, и он обязательно понадобится вам позже.
Единственная схема, которая имеет для меня смысл, такова:
Person
PersonID Int PK
Friend
PersonID Int PK FK
OtherPersonID Int PK FK
Итак, у вас может быть процедура под названием FriendList
, которая выполняет этот красивый чистый запрос:
Select Person.*
From Friend
Inner Join Person On Friend.OtherPersonID = Person.PersonID
Where Friend.PersonID = @PersonID;
Я не одобряю выбор всех столбцов.