Управління окремою інформацією
Припустимо, що у вашому домені бізнесу
- Користувач може мати нульові один або багато друг ;
- Друг повинен першим бути зареєстрований в якості користувача ; і
- ви будете шукати та / або додавати, та / або вилучати та / або змінювати поодинокі значення списку друзів ;
то кожна конкретна дата, зібрана у Friendlist_IDs
багатозначному стовпчику, являє собою окрему інформацію, яка має дуже точне значення. Тому зазначена колонка
- тягне за собою належну групу явних обмежень та
- його значення можуть піддаватися маніпулюванню окремо за допомогою декількох реляційних операцій (або їх комбінацій).
Коротка відповідь
Отже, вам слід зберегти кожне зі Friendlist_IDs
значень у (а) стовпці, який приймає виключно одне єдине значення на рядок у (b) таблиці, яка представляє тип асоціації на концептуальному рівні, який може відбуватися між Користувачами , тобто Дружба - як Я прикладу приклади в наступних розділах.
Таким чином, ви зможете обробити (i) зазначену таблицю як математичне відношення, і (ii) вказаний стовпець як атрибут математичного відношення - настільки ж, як дозволяє MySQL та його діалект SQL, звичайно -.
Чому?
Оскільки реляційна модель даних , створена доктором Е. Ф. Коддом , вимагає мати таблиці, що складаються з стовпців, що містять рівно одне значення відповідного домену чи типу в рядку; отже, оголошення таблиці зі стовпцем, яка може містити більше одного значення домену чи типу, про які йдеться (1), не представляє математичного відношення і (2) не дозволить отримати переваги, запропоновані у вищезгаданій теоретичній базі.
Моделювання дружби між користувачами : Спочатку визначте правила ділового середовища
Я настійно рекомендую почати формувати базу даних, що обмежує - перш за все інше - відповідну концептуальну схему в силу визначення відповідних правил ведення бізнесу, які, серед інших факторів, повинні описувати типи взаємозв'язків, що існують між різними аспектами інтересу, тобто , типи юридичних осіб та їх властивості ; наприклад:
- Користувач в першу чергу ідентифікується його UserId
- Користувач черзі визначається комбінацією його або її FirstName , LastName , Пол і народження
- Користувач черзі ідентифікується його Ім'я
- Користувач є Запитом нульових один або-багато Дружби
- Користувач є Адресат нульовий один або-багато Дружби
- Дружба в першу чергу визначається комбінацією його RequesterId і його AddresseeId
Діаграма IDEF1X експозиторії
Таким чином, я зміг отримати схему IDEF1X 1, показану на рисунку 1 , яка інтегрує більшість правил, сформульованих раніше:
Як зображено, Заявник та Адресат - це позначення, які виражають ролі, які виконуються конкретними Користувачами, які беруть участь у певній дружбі .
Оскільки це так, то дружба тип сутності зображує вид Асоціації багато-до-багатьох (M: N) відношення потужності , що може включати в себе різні входжень в той же тип об'єкта, тобто користувача . Як такий, він є прикладом класичної конструкції, відомої як "Біблія матеріалів" або "Вибух частин".
1 Визначення інтеграції для інформаційного моделювання ( IDEF1X ) - це дуже рекомендована методика, яка була встановлена як стандарт в грудні 1993 р. Національним інститутом стандартів і технологій США (NIST). Це ґрунтується на (a) ранньому теоретичному матеріалі, створеному єдиним автором реляційної моделі, тобто доктором Е.Ф. Коддом ; (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
стовпця, оскільки обмеження її як ІНОЗЕМНИЙ КЛЮЧ (FK для стислості), що робить посилання на UserProfile.UserId
стовпець, гарантує, що кожне значення вказує на існуючий рядок.
Створіть складений ОСНОВНИЙ КЛЮЧ (ПК), складений із комбінації стовпців (Friendship.RequesterId, Friendship.AddresseeId)
, що допомагає елегантно розрізнити всі ВСТАНОВІ ряди та, природно, захистити їх унікальність .
Звичайно, це означає, що додавання додаткового стовпчика для сурогатних значень, призначених системою (наприклад, одного, встановленого з властивістю IDENTITY в Microsoft SQL Server або з атрибутом AUTO_INCREMENT в MySQL) та допоміжного INDEX є абсолютно зайвим .
Обмежте збережені значення у Friendship.AddresseeId
точному типі даних c (який повинен відповідати, наприклад, встановленому для UserProfile.UserId
, у цьому випадку INT), дозволяючи СУБД дбати про відповідну автоматичну перевірку.
Цей фактор може також допомогти (a) використовувати відповідні функції вбудованого типу та (b) оптимізувати використання дискового простору .
Оптимізуйте пошук даних на фізичному рівні, конфігурувавши невеликі та швидкі підпорядковані INDEXе для Friendship.AddresseeId
стовпця, оскільки ці фізичні елементи можуть істотно допомогти у прискоренні запитів, що стосуються зазначеного стовпця.
Звичайно, ви можете, наприклад, поставити одноколонний INDEX для Friendship.AddresseeId
одного, багато стовпця, який охоплює Friendship.RequesterId
та Friendship.AddresseeId
або обидва.
Уникайте зайвої складності, введеної "пошуком" відмінних значень, які збираються всередині одного і того ж стовпця (швидше за все, дублюється, неправильно набрано тощо), ходу дій, яка в кінцевому підсумку уповільнить функціонування вашої системи, тому що ви б доведеться вдатися до ресурсних і трудомістких нереляційних методів для виконання зазначеного завдання.
Отже, є кілька причин, які вимагають ретельного аналізу відповідного бізнес-середовища, щоб точно позначити тип d кожного стовпця таблиці.
Як пояснено, роль, яку відіграє конструктор баз даних, є першорядною для найкращого використання (1) переваг логічного рівня, пропонованих реляційною моделлю, та (2) фізичних механізмів, що надаються СБД на вибір.
a , b , c , d Очевидно, що під час роботи з платформами SQL (наприклад, Firebird та PostgreSQL ), які підтримують створення DOMAIN (відмітна реляційна особливість), ви можете оголошувати стовпці, які приймають лише ті значення, які належать до їх відповідних (що сильно обмежено і іноді спільно) DOMAIN.
Одна або кілька прикладних програм, що обмінюються розглянутою базою даних
Коли ви повинні використовувати arrays
в коді прикладної програми (и) екранної базу даних, вам просто потрібно , щоб отримати відповідний набір даних (и) в повному обсязі , а потім «прив'язати» його (їх) до відносно структури коди або виконайте пов'язаний процес (и) додатків, який має відбутися.
Подальші переваги однозначних стовпців: Розширення структури бази даних набагато простіше
Ще одна перевага зберігання AddresseeId
точки даних у зарезервованому та належним чином введеному стовпчику полягає в тому, що це значно полегшує розширення структури бази даних, як я поясню нижче.
Прогресування сценарію: Включення концепції дружби
Оскільки дружба може розвиватися з часом, вам, можливо, доведеться відслідковувати таке явище, тому вам доведеться (i) розширити концептуальну схему та (ii) оголосити ще кілька таблиць у логічному макеті. Отже, давайте організуємо наступні правила ведення бізнесу для розмежування нових корпорацій:
- Дружба займає один-ко-многим FriendshipStatuses
- FriendshipStatus в першу чергу визначається комбінацією його RequesterId , його AddresseeId і його SpecifiedDateTime
- A User визначає нуль-один-або-багато FriendshipStatuses
- A Статус класифікує нуль-один-або-багато FriendshipStatuses
- Статус головним чином ідентифікується своїм StatusCode
- Статус черзі ідентифікується по його імені
Розширена діаграма IDEF1X
Послідовно попередня діаграма IDEF1X може бути розширена, щоб включити нові типи сутностей та типи взаємозв'язків, описані вище. Діаграма, що зображує попередні елементи, пов'язані з новими, представлена на рисунку 2 :
Доповнення логічної структури
Після цього ми можемо подовжити макет 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
-;
точний момент INSERTion, тобто, SpecifiedDateTime
переважно, використовуючи функцію сервера, щоб ви могли отримати і зберегти її надійно; і
SpecifierId
значення , яке буде вказувати відповідне , UserId
що увійшло в новому FriendshipStatus
в систему -ideally, за допомогою вашої програми (s) точки-.
Припустимо, що у MyStatus
таблицю містяться такі дані - із значеннями ПК, які (а) є кінцевим користувачем, програмістом додатків та зручним для DBA та (б) малим та швидким у перерахунку на байти на рівні фізичної реалізації -:
+ -——————————— + +——————————— +
| StatusCode | Назва |
+ -——————————— + +——————————— +
| R | Запитано |
+ ------------ + ----------- +
| А | Прийнято |
+ ------------ + ----------- +
| Д | Відхилено |
+ ------------ + ----------- +
| Б | Заблоковано |
+ ------------ + ----------- +
Отже, FriendshipStatus
таблиця може містити дані, як показано нижче:
+ -———————————— + +———————————————————————————————————————— ———- + -——————————— + -———————————— +
| RequesterId | АдресатId | SpecifiedDateTime | StatusCode | SpecifierId |
+ -———————————— + +———————————————————————————————————————— ———- + -——————————— + -———————————— +
| 1750 | 1748 | 2016-04-01 16: 58: 12.000 | R | 1750 |
+ ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
| 1750 | 1748 | 2016-04-02 09: 12: 05.000 | А | 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 | А | 1750 |
+ ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
Як бачите, можна сказати, що FriendshipStatus
таблиця служить меті, що включає часовий ряд .
Відповідні повідомлення
Вас також можуть зацікавити:
- Ця відповідь, в якій я пропоную основний метод для вирішення загальної взаємозв'язку між багатьма різними типами сутності.
- Діаграма IDEF1X, показана на рисунку 1, що ілюструє цю іншу відповідь . Зверніть особливу увагу на типи сутностей під назвою " Шлюб та потомство" , оскільки вони є ще двома прикладами, як вирішити "Проблему вибуху частин".
- Ця публікація, в якій представлено коротке обговорення щодо зберігання різних відомостей у межах однієї колонки.