Разработка структуры базы данных о дружбе. Должен ли я использовать многозначный столбец?

9

Скажем, у меня есть таблица User_FriendList, которая имеет следующие характеристики:

CREATE TABLE User_FriendList (
    ID ...,
    User_ID...,
    FriendList_IDs...,
    CONSTRAINT User_Friendlist_PK PRIMARY KEY (ID)
);

И предположим, что указанная таблица содержит следующие данные:

 + ---- + --------- + --------------------------- +
 | ID | Идентификатор пользователя | Friendlist_IDs             |
 + ---- + --------- + --------------------------- +
 | 1 | 102 | 2: 15: 66: 35: 26: 17: |
 + ---- + --------- + --------------------------- +
 | 2 | 114 | 1: 12: 63: 33: 24: 16: 102 |
 + ---- + --------- + --------------------------- +
 | 3 | 117 | 6: 24: 52: 61: 23: 90: 97: 118 |
 + ---- + --------- + --------------------------- +

Примечание: «:» (двоеточие) - это разделитель при разбиении в PHP на array.

Вопросов

Так:

  • Это удобный способ «магазин» IDsиз FriendList?

  • Или вместо этого я должен иметь отдельные строки с одним единственным FriendIdзначением в каждой из них и, когда мне нужно получить все строки данного списка , просто выполнить запрос как SELECT * FROM UserFriendList WHERE UserId = 1?

yeln
источник
3
Я рекомендую вам прочитать это: stackoverflow.com/questions/3653462/…
tombom
Это несколько удобный способ хранения идентификаторов, если вы не планируете ничего с ними делать и не особенно заботитесь о качестве данных.
Mustaccio
Я думаю, codedodle.com/2014/12/social-network-friends-database.html может быть одним из лучших решений.
Гупта

Ответы:

19

Управление отдельной частью информации

Предполагая, что в вашей сфере бизнеса,

  • Пользователь может иметь нулевые один или многие друг ;
  • Друг должен первым быть зарегистрирован в качестве пользователя ; а также
  • вы будете искать, и / или добавлять, и / или удалять, и / или изменять отдельные значения списка друзей ;

затем каждый конкретный элемент данных, собранный в Friendlist_IDsмногозначном столбце, представляет отдельный фрагмент информации, который имеет очень точное значение. Следовательно, указанный столбец

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

Короткий ответ

Следовательно, вы должны сохранить каждое из Friendlist_IDsзначений в (a) столбце, который принимает только одно единственное значение на строку в (b) таблице, которая представляет тип ассоциации концептуального уровня, который может иметь место между пользователями , то есть дружбу - как Я приведу пример в следующих разделах.

Таким образом, вы сможете обрабатывать (i) указанную таблицу как математическое отношение и (ii) указанный столбец как атрибут математического отношения - насколько это возможно, конечно, в MySQL и его диалекте SQL.

Почему?

Поскольку реляционная модель данных , созданная д-ром Э. Ф. Коддом , требует наличия таблиц, состоящих из столбцов, которые содержат ровно одно значение соответствующего домена или типа на строку; следовательно, объявление таблицы со столбцом, который может содержать более одного значения рассматриваемого домена или типа (1), не представляет математического отношения, а (2) не позволит получить преимущества, предложенные в вышеупомянутой теоретической структуре.

Моделирование дружеских отношений между пользователями : сначала необходимо определить правила бизнес-среды

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

  • Пользователь в первую очередь идентифицируется его UserId
  • Пользователь поочередно определяется комбинацией его или ее FirstName , LastName , Пол и рождения
  • Пользователь поочередно идентифицируется его Имя
  • Пользователь является Запросом нулевых один или-много Дружбы
  • Пользователь является Адресат нулевой один или-много Дружбы
  • Дружба в первую очередь определяется комбинацией его RequesterId и его AddresseeId

Описательная схема IDEF1X

Таким образом, я смог вывести диаграмму IDEF1X 1 , показанную на рисунке 1 , которая объединяет большинство ранее сформулированных правил:

Рисунок 1. Диаграмма дружбы пользователей IDEF1X

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

Таким образом, тип сущности « Дружба » отображает тип ассоциации отношения множества ко многим (M: N), который может включать различные вхождения одного и того же типа сущности, то есть пользователя . Таким образом, это пример классической конструкции, известной как «ведомость материалов» или «взрыв деталей».


1 Определение интеграции для информационного моделирования ( IDEF1X ) - это очень рекомендуемый метод, который был принят в качестве стандарта в декабре 1993 года Национальным институтом стандартов и технологий США (NIST). Он основывается на (а) раннем теоретическом материале, автором которого является единственный создатель реляционной модели, т. Е. Доктор Э. Ф. Кодд ; (b)представление данных об отношениях между сущностями, разработанное доктором П.П. Ченом ; а также о (c) методике проектирования логических баз данных, созданной Робертом Г. Брауном.


Иллюстративный логический дизайн SQL-DDL

Затем, из диаграммы IDEF1X, представленной выше, объявление схемы DDL, подобной той, что следует, является гораздо более «естественным»:

-- You should determine which are the most fitting 
-- data types and sizes for all the table columns 
-- depending on your business context characteristics.

-- At the physical level, you should make accurate tests 
-- to define the mostconvenient INDEX strategies based on 
-- the pertinent query tendencies.

-- As one would expect, you are free to make use of 
-- your preferred (or required) naming conventions. 

CREATE TABLE UserProfile ( -- Represents an independent entity type.
    UserId          INT      NOT NULL,
    FirstName       CHAR(30) NOT NULL,
    LastName        CHAR(30) NOT NULL,
    BirthDate       DATE     NOT NULL,
    GenderCode      CHAR(3)  NOT NULL,
    Username        CHAR(20) NOT NULL,
    CreatedDateTime DATETIME NOT NULL,
    --
    CONSTRAINT UserProfile_PK  PRIMARY KEY (UserId),
    CONSTRAINT UserProfile_AK1 UNIQUE ( -- Composite ALTERNATE KEY.
        FirstName,
        LastName,
        GenderCode,
        BirthDate
    ),
    CONSTRAINT UserProfile_AK2 UNIQUE (Username) -- Single-column ALTERNATE KEY.
);

CREATE TABLE Friendship ( -- Stands for an associative entity type.
    RequesterId     INT      NOT NULL,
    AddresseeId     INT      NOT NULL, -- Fixed with a well-delimited data type.
    CreatedDateTime DATETIME NOT NULL,
    --
    CONSTRAINT Friendship_PK            PRIMARY KEY (RequesterId, AddresseeId), -- Composite PRIMARY KEY.
    CONSTRAINT FriendshipToRequester_FK FOREIGN KEY (RequesterId)
        REFERENCES UserProfile (UserId),
    CONSTRAINT FriendshipToAddressee_FK FOREIGN KEY (AddresseeId)
        REFERENCES UserProfile (UserId)
);

Таким образом:

  • каждая базовая таблица представляет отдельный тип объекта;
  • каждый столбец обозначает единственное свойство соответствующего типа объекта;
  • конкретный тип данных a фиксирован для каждого столбца , чтобы гарантировать, что все содержащиеся в нем значения принадлежат конкретному и четко определенному набору , будь то INT, DATETIME, CHAR и т. д .; а также
  • несколько ограничений b настроены (декларативно), чтобы гарантировать, что утверждения в виде строк, сохраняемых во всех таблицах, соответствуют бизнес-правилам, определенным в концептуальной схеме.

Преимущества однозначного столбца

Как продемонстрировано, вы можете, например:

  • Воспользуйтесь преимуществом ссылочной целостности, обеспечиваемой системой управления базами данных (для краткости СУБД) для Friendship.AddresseeIdстолбца, поскольку ограничение его как FOREIGN KEY (FK для краткости), которое делает ссылку на UserProfile.UserIdстолбец, гарантирует, что каждое значение указывает на существующую строку.

  • Создайте составной PRIMARY KEY (PK), состоящий из комбинации столбцов (Friendship.RequesterId, Friendship.AddresseeId), помогая элегантно различать все INSERTed-строки и, естественно, защищать их уникальность .

    Конечно, это означает, что вложение дополнительного столбца для присваиваемых системой суррогатных значений (например, столбца, настроенного с помощью свойства IDENTITY в Microsoft SQL Server или с атрибутом AUTO_INCREMENT в MySQL) и вспомогательного INDEX полностью излишни .

  • Ограничьте сохраняемые значения Friendship.AddresseeIdточным типом данных c (который должен соответствовать, например, типу , установленному для UserProfile.UserId, в данном случае INT), позволяя СУБД позаботиться о соответствующей автоматической проверке.

    Этот фактор также может помочь (а) использовать соответствующие функции встроенного типа и (б) оптимизировать использование дискового пространства .

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

    Конечно, вы можете, например, расфасованные одну колонку для Friendship.AddresseeIdодин, с несколькими столбцами тот , который включает в себя Friendship.RequesterIdи Friendship.AddresseeId, или обоих.

  • Избегайте ненужной сложности, связанной с «поиском» отдельных значений, которые собираются вместе в одном столбце (очень вероятно, дублируются, ошибочно набраны и т. Д.), Курсом действий, который в конечном итоге замедлит функционирование вашей системы, потому что вы бы для выполнения указанной задачи приходится прибегать к ресурсо- и трудоемким нереляционным методам.

Таким образом, существует множество причин, требующих тщательного анализа соответствующей бизнес-среды, чтобы точно определить тип d каждого столбца таблицы.

Как указывалось выше, роль, которую играет разработчик базы данных, имеет первостепенное значение для наилучшего использования (1) преимуществ логического уровня, предлагаемых реляционной моделью, и (2) физических механизмов, предоставляемых выбранной СУБД.


a , b , c , d Очевидно, что при работе с платформами SQL (например, Firebird и PostgreSQL ), которые поддерживают создание DOMAIN (отличительная реляционная особенность), вы можете объявлять столбцы, которые принимают только значения, принадлежащие их соответствующим (соответствующим образом ограниченным и иногда поделился) ДОМЕНЫ.


Одна или несколько прикладных программ, совместно использующих рассматриваемую базу данных

Когда вы должны использовать arraysв коде прикладной программы (ы) экранной базу данных, вам просто нужно , чтобы получить соответствующий набор данных (ы) в полном объеме , а затем «привязать» его (их) к относительно структуры коды или выполните связанный процесс (ы) приложения, которые должны иметь место.

Дополнительные преимущества однозначных столбцов: расширения структуры базы данных намного проще

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

Сценарий развития: внедрение концепции статуса дружбы

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

  • Дружба занимает один-ко-многим FriendshipStatuses
  • FriendshipStatus в первую очередь определяется комбинацией его RequesterId , его AddresseeId и его SpecifiedDateTime
  • A User определяет ноль-один-или-много FriendshipStatuses
  • A Статус классифицирует ноль-один-или-много FriendshipStatuses
  • Статус главным образом идентифицируется своим StatusCode
  • Статус поочередно идентифицируется по его имени

Расширенная диаграмма IDEF1X

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

Рисунок 2. Диаграмма состояния дружбы IDEF1X

Логическая структура дополнения

После этого мы можем удлинить макет DDL с помощью следующих объявлений:

--
CREATE TABLE MyStatus ( -- Denotes an independent entity type.
    StatusCode CHAR(1)  NOT NULL,
    Name       CHAR(30) NOT NULL,
    --
    CONSTRAINT MyStatus_PK PRIMARY KEY (StatusCode),
    CONSTRAINT MyStatus_AK UNIQUE      (Name) -- ALTERNATE KEY.
); 

CREATE TABLE FriendshipStatus ( -- Represents an associative entity type.
    RequesterId       INT      NOT NULL,
    AddresseeId       INT      NOT NULL,
    SpecifiedDateTime DATETIME NOT NULL,
    StatusCode        CHAR(1)  NOT NULL,
    SpecifierId       INT      NOT NULL,
    --
    CONSTRAINT FriendshipStatus_PK             PRIMARY KEY (RequesterId, AddresseeId, SpecifiedDateTime), -- Composite PRIMARY KEY.
    CONSTRAINT FriendshipStatusToFriendship_FK FOREIGN KEY (RequesterId, AddresseeId)
        REFERENCES Friendship  (RequesterId, AddresseeId), -- Composite FOREIGN KEY.
    CONSTRAINT FriendshipStatusToMyStatus_FK   FOREIGN KEY (StatusCode)
        REFERENCES MyStatus    (StatusCode),
    CONSTRAINT FriendshipStatusToSpecifier_FK  FOREIGN KEY (SpecifierId)
        REFERENCES UserProfile (UserId)      
);

Следовательно, каждый раз, когда необходимо обновить Состояние данной Дружбы , Пользователям нужно будет только ВСТАВИТЬ новую FriendshipStatusстроку, содержащую:

  • подходящие RequesterIdи AddresseeIdценности, взятые из соответствующей строки Friendship;

  • новая и значимая StatusCodeценность - взято из MyStatus.StatusCode-;

  • точный момент ВСТАВКИ, т. е. - SpecifiedDateTimeпредпочтительно с использованием серверной функции, чтобы вы могли надежно извлекать и сохранять ее; а также

  • SpecifierIdзначение , которое будет указывать соответствующее , UserIdчто вошло в новом FriendshipStatusв систему -ideally, с помощью вашего приложения (s) точки-.

В связи с этим предположим, что MyStatusтаблица включает в себя следующие данные - со значениями PK, которые (a) удобны для конечного пользователя, программиста приложения и администратора баз данных и (b) малы и быстры с точки зрения байтов на физическом уровне реализации -:

 + ------------ + ----------- +
 | StatusCode | Имя       |
 + ------------ + ----------- +
 | R | Запрошено |
 + ------------ + ----------- +
 | A | Принято |
 + ------------ + ----------- +
 | D | Отклонено |
 + ------------ + ----------- +
 | Б | Bloqued |
 + ------------ + ----------- +

Таким образом, FriendshipStatusтаблица может содержать данные, как показано ниже:

 + ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
 | RequesterId | Адрес получателя | SpecifiedDateTime        | StatusCode | SpecifierId |
 + ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
 | 1750 | 1748 | 2016-04-01 16: 58: 12.000 | R | 1750 |
 + ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
 | 1750 | 1748 | 2016-04-02 09: 12: 05.000 | A | 1748 |
 + ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
 | 1750 | 1748 | 2016-04-04 10: 57: 01.000 | Б | 1750 |
 + ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
 | 1750 | 1748 | 2016-04-07 07: 33: 08.000 | R | 1748 |
 + ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
 | 1750 | 1748 | 2016-04-08 12: 12: 09.000 | A | 1750 |
 + ------------- + ------------- + --------------------- ---- + ------------ + ------------- +

Как видите, можно сказать, что FriendshipStatusтаблица служит для составления временного ряда .


Соответствующие сообщения

Вы также можете быть заинтересованы в:

  • Этот ответ, в котором я предлагаю базовый метод для решения общих отношений «многие ко многим» между двумя разными типами сущностей.
  • Диаграмма IDEF1X, показанная на рисунке 1, иллюстрирует этот другой ответ . Обратите особое внимание на типы сущностей с именами Marriage и Progeny , потому что они являются еще двумя примерами того, как справиться с «проблемой взрыва деталей».
  • Этот пост , в котором кратко обсуждается, как хранить разные фрагменты информации в одном столбце.
MDCCL
источник