Zarządzanie pojedynczą informacją
Zakładając, że w Twojej domenie biznesowej
- Użytkownik może mieć zero-jeden-lub-wielu przyjaciół ;
- Friend musi najpierw zostać zarejestrowany jako użytkownik ; i
- będziesz wyszukiwał i / lub dodawał i / lub usuwał i / lub modyfikował pojedyncze wartości Listy znajomych ;
następnie każdy konkretny punkt odniesienia zebrany w Friendlist_IDs
kolumnie wielowartościowej reprezentuje oddzielną informację, która ma bardzo dokładne znaczenie. Dlatego wspomniana kolumna
- pociąga za sobą odpowiednią grupę wyraźnych ograniczeń oraz
- jego wartości mogą być manipulowane indywidualnie za pomocą kilku operacji relacyjnych (lub ich kombinacji).
Krótka odpowiedź
W związku z tym powinieneś zachować każdą z Friendlist_IDs
wartości w (a) kolumnie, która akceptuje tylko jedną wyłączną wartość na wiersz w (b) tabeli, która reprezentuje typ powiązania na poziomie koncepcyjnym, który może mieć miejsce między użytkownikami , tj. Przyjaźń - jako Zilustruję to następującymi sekcjami—.
W ten sposób będziesz w stanie obsłużyć (i) wspomnianą tabelę jako relację matematyczną oraz (ii) wspomnianą kolumnę jako atrybut relacji matematycznej - podobnie jak MySQL i oczywiście jego dialekt SQL - oczywiście.
Dlaczego?
Ponieważ relacyjny model danych , stworzony przez dr E. F. Codda , wymaga posiadania tabel składających się z kolumn zawierających dokładnie jedną wartość odpowiedniej domeny lub typu na wiersz; dlatego zadeklarowanie tabeli z kolumną, która może zawierać więcej niż jedną wartość domeny lub typu, o którym mowa (1), nie reprezentuje relacji matematycznej i (2) nie pozwoliłoby na uzyskanie korzyści zaproponowanych w wyżej wymienionych ramach teoretycznych.
Modelowanie przyjaźni między użytkownikami : Najpierw należy zdefiniować reguły środowiska biznesowego
Zdecydowanie zalecam rozpoczęcie tworzenia bazy danych określającej - przed czymkolwiek innym - odpowiedni schemat pojęciowy na podstawie definicji odpowiednich reguł biznesowych, które między innymi muszą opisywać rodzaje wzajemnych powiązań między różnymi aspektami zainteresowania, tj. , odpowiednie typy jednostek i ich właściwości ; na przykład:
- Użytkownik jest identyfikowany głównie przez jego UserId
- Użytkownik jest naprzemiennie zidentyfikowane przez połączenie jego FirstName , LastName , płci i urodzenia
- Użytkownik jest naprzemiennie zidentyfikowane przez jego Nazwa użytkownika
- Użytkownik jest Requestera zero-jeden-or-wieloma przyjaźniami
- Użytkownik jest Adresat zero-jeden-or-wieloma przyjaźniami
- Przyjaźń jest identyfikowana głównie przez połączenie jej RequesterId i jego AddresseeId
Schemat IDEF1X dla ekspozytora
W ten sposób udało mi się uzyskać diagram IDEF1X 1 pokazany na rysunku 1 , który integruje większość wcześniej sformułowanych reguł:
Jak pokazano, Wnioskodawca i Adresat są oznaczeniami, które wyrażają Role realizowane przez konkretnych Użytkowników biorących udział w danej Przyjaźni .
W związku z tym typ encji Przyjaźń przedstawia typ asocjacji o stosunku liczności wiele do wielu (M: N), który może obejmować różne przypadki tego samego typu encji, tj . Użytkownika . Jako taki, jest to przykład klasycznej konstrukcji znanej jako „Zestawienie materiałów” lub „Wybuch części”.
1 Integration Definition for Information Modeling ( IDEF1X ) to wysoce godna polecenia technika, która została ustanowiona jako standard w grudniu 1993 r. Przez amerykański Narodowy Instytut Norm i Technologii (NIST). Jest solidnie oparty na (a) wczesnym materiale teoretycznym autorstwa jedynego twórcy modelu relacyjnego, tj. Dr EF Codda ; na (b)widok danych relacji jednostka , opracowany przez dr PP Chen ; a także w (c) Logical Database Design Technique, stworzonej przez Roberta G. Browna.
Ilustracyjny logiczny projekt SQL-DDL
Następnie, zgodnie ze schematem IDEF1X przedstawionym powyżej, zadeklarowanie układu DDL, takiego jak poniższy, jest znacznie bardziej „naturalne”:
-- 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)
);
W ten sposób:
- każda tabela podstawowa reprezentuje indywidualny typ jednostki;
- każda kolumna oznacza wyłączną właściwość odpowiedniego typu jednostki;
- określony typ danych a jest ustalony dla każdej kolumny , aby zagwarantować, że wszystkie zawarte w nim wartości należą do określonego i dobrze zdefiniowanego zestawu , czy to INT, DATETIME, CHAR itp .; i
- wiele ograniczeń b jest konfigurowanych (deklaratywnie) w celu zapewnienia, że twierdzenia w postaci wierszy zachowane we wszystkich tabelach spełniają reguły biznesowe określone na schemacie koncepcyjnym.
Zalety kolumny o pojedynczej wartości
Jak wykazano, możesz np .:
Skorzystaj z integralności referencyjnej wymuszonej przez system zarządzania bazą danych (DBMS dla zwięzłości) dla Friendship.AddresseeId
kolumny, ponieważ ograniczenie jej jako KLUCZA OBCEGO (FK dla zwięzłości), który odnosi się do UserProfile.UserId
kolumny, gwarantuje, że każda wartość wskazuje na istniejący wiersz.
Utwórz złożony KLUCZ PODSTAWOWY (PK) złożony z kombinacji kolumn (Friendship.RequesterId, Friendship.AddresseeId)
, pomagając elegancko odróżnić wszystkie WSTAWIONE rzędy i, naturalnie, chronić ich wyjątkowość .
Oczywiście oznacza to, że dołączenie dodatkowej kolumny dla przypisanych przez system wartości zastępczych (np. Skonfigurowanej z właściwością IDENTITY w Microsoft SQL Server lub z atrybutem AUTO_INCREMENT w MySQL) i INDEKS pomocniczy jest całkowicie zbędny .
Ogranicz zachowane wartości Friendship.AddresseeId
do dokładnego typu danych c (który powinien pasować np. Do tego ustalonego dla UserProfile.UserId
, w tym przypadku INT), pozwalając DBMS zająć się odpowiednią automatyczną weryfikacją.
Ten czynnik może również pomóc (a) wykorzystać odpowiednie wbudowane funkcje typu i (b) zoptymalizować wykorzystanie miejsca na dysku .
Zoptymalizuj pobieranie danych na poziomie fizycznym, konfigurując małe i szybkie INDEKSY podrzędne dla Friendship.AddresseeId
kolumny, ponieważ te fizyczne elementy mogą znacznie pomóc w przyspieszeniu zapytań dotyczących tej kolumny.
Oczywiście, możesz np. Ustawić INDEKS jednokolumnowy dla Friendship.AddresseeId
samego, wielokolumnowy, który obejmuje Friendship.RequesterId
i Friendship.AddresseeId
, lub jedno i drugie.
Unikaj niepotrzebnej złożoności wprowadzonej przez „wyszukiwanie” odrębnych wartości, które są gromadzone razem w tej samej kolumnie (najprawdopodobniej powielone, źle wpisane itp.), Co może spowolnić działanie systemu, ponieważ muszą skorzystać z czasochłonnych zasobów i metod nierelacyjnych, aby wykonać to zadanie.
Istnieje zatem wiele powodów, które wymagają dokładnej analizy odpowiedniego środowiska biznesowego w celu dokładnego zaznaczenia typu d każdej kolumny tabeli.
Jak wyjaśniono, rola projektanta bazy danych jest najważniejsza, aby jak najlepiej wykorzystać (1) korzyści na poziomie logicznym oferowane przez model relacyjny oraz (2) mechanizmy fizyczne zapewniane przez wybrany DBMS.
, b , c , d Widocznie podczas pracy z platformami SQL (np Firebird i PostgreSQL ), że tworzenie wsparcie domeny (charakterystyczny relacyjny funkcję), można zadeklarować kolumn tylko przyjąć wartości, które należą do ich prawnych (słusznie ograniczone, a czasem udostępnione) DOMAIN.
Jeden lub więcej aplikacji współdzielących rozważaną bazę danych
Gdy musisz zastosować arrays
kod aplikacji, które uzyskują dostęp do bazy danych, musisz po prostu pobrać odpowiednie zestawy danych w całości, a następnie „powiązać” je z odpowiednią strukturą kodu lub wykonać powiązane procesy, które powinny mieć miejsce.
Dalsze zalety kolumn o jednej wartości: Rozszerzenia struktury bazy danych są znacznie łatwiejsze
Kolejną zaletą trzymania AddresseeId
punktu danych w zarezerwowanej i odpowiednio wpisanej kolumnie jest to, że znacznie ułatwia rozszerzenie struktury bazy danych, co zilustruję poniżej.
Postęp scenariusza: włączenie koncepcji statusu przyjaźni
Ponieważ przyjaźnie mogą ewoluować w czasie, być może będziesz musiał śledzić takie zjawisko, więc będziesz musiał (i) rozwinąć schemat koncepcyjny i (ii) zadeklarować kilka dodatkowych tabel w układzie logicznym. A zatem, ustalmy kolejne reguły biznesowe, aby nakreślić nowe włączenia:
- Przyjaźń posiada jeden-do-wielu FriendshipStatuses
- Status FriendshipStatus jest przede wszystkim identyfikowany przez kombinację jego RequesterId , AddresseeId i SpecifiedDateTime
- A Użytkownika określa zero-jeden-or-wiele FriendshipStatuses
- A Stan klasyfikuje zero-jeden-or-wiele FriendshipStatuses
- Stan jest identyfikowana głównie przez jego StatusCode
- Stan jest naprzemiennie zidentyfikowane przez jego nazwy
Rozszerzony schemat IDEF1X
Sukcesywnie poprzedni schemat IDEF1X można rozszerzyć, aby uwzględnić nowe typy jednostek i typy powiązań opisane powyżej. Schemat przedstawiający poprzednie elementy związane z nowymi przedstawiono na rysunku 2 :
Uzupełnienia struktury logicznej
Następnie możemy wydłużyć układ DDL o następujące deklaracje:
--
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)
);
W związku z tym za każdym razem, gdy status danej przyjaźni musi być aktualizowany, użytkownicy będą musieli WSTAWIĆ tylko nowy FriendshipStatus
wiersz zawierający:
odpowiednie RequesterId
i AddresseeId
wartości - wzięte z odpowiedniego wiersza - Friendship
;
nowa i znacząca StatusCode
wartość - zaczerpnięta z MyStatus.StatusCode
-;
dokładna chwila WSTAWIANIA, tj. - SpecifiedDateTime
najlepiej przy użyciu funkcji serwera, aby można było ją pobrać i zachować w niezawodny sposób -; i
SpecifierId
wartość, która wskazuje odpowiedni UserId
która weszła nowa FriendshipStatus
w systemie -ideally, przy pomocy aplikacji (s) facilities-.
W tym zakresie załóżmy, że MyStatus
tabela zawiera następujące dane - z wartościami PK, które są (a) przyjazne dla użytkownika końcowego, programisty aplikacji i DBA oraz (b) małe i szybkie pod względem bajtów na poziomie implementacji fizycznej -:
+ -——————————- + -—————————- +
| StatusCode | Imię |
+ -——————————- + -—————————- +
| R | Prośba |
+ ------------ + ----------- +
| A | Zaakceptowano |
+ ------------ + ----------- +
| D | Odrzucony |
+ ------------ + ----------- +
| B | Bloqued |
+ ------------ + ----------- +
Tak więc FriendshipStatus
tabela może zawierać dane, jak pokazano poniżej:
+ -———————————- + -———————————- + -——————————————————— ———- + -——————————- + -———————————- +
| RequesterId | Adresat | SpecifiedDateTime | StatusCode | SpecifierId |
+ -———————————- + -———————————- + -——————————————————— ———- + -——————————- + -———————————- +
| 1750 | 1748 | 01.04.2016, 16: 58: 12.000 | R | 1750 |
+ ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
| 1750 | 1748 | 02.04.2016 09: 12: 05.000 | A | 1748 |
+ ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
| 1750 | 1748 | 04.04.2016 10: 57: 01.000 | B | 1750 |
+ ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
| 1750 | 1748 | 07.04.2016, 07: 33: 08.000 | R | 1748 |
+ ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
| 1750 | 1748 | 2016-04-08 12: 12: 09.000 | A | 1750 |
+ ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
Jak widać, można powiedzieć, że FriendshipStatus
tabela służy szeregowi czasowemu .
Odpowiednie posty
Równie interesujące mogą być:
- Ta odpowiedź, w której sugeruję podstawową metodę radzenia sobie ze wspólną relacją wiele do wielu między dwoma różnymi typami bytów.
- Schemat IDEF1X pokazany na rycinie 1 ilustrujący tę drugą odpowiedź . Zwróć szczególną uwagę na typy jednostek o nazwie Małżeństwo i potomstwo , ponieważ są to dwa kolejne przykłady radzenia sobie z „Problemem eksplozji części”.
- Ten post przedstawia krótkie rozważania na temat przechowywania różnych informacji w jednej kolumnie.