Na starej bazie kodu pojawiło się nowe wymaganie, które zasadniczo umożliwia bezpośrednią (wewnętrzną) komunikację między dwiema poprzednio nie bezpośrednio powiązanymi klasami użytkowników (przechowywanymi w różnych tabelach z zupełnie innym schematem) i, niestety, kod jest ledwie świadomy OO, wiele mniej zaprojektowane, więc nie ma klasy nadrzędnej). Ponieważ mamy zamiar zawiesić torbę na tej starej konfiguracji, która nigdy nie rozważała tej funkcjonalności, nie ma gwarancji, że nie wystąpią kolizje PK - biorąc pod uwagę używany zestaw danych, jest praktycznie gwarantowane, że SĄ.
Tak więc rozwiązanie wydaje się oczywiste: zabij go ogniem i przepisz cały bałagan Tabela map. Dostałem dwa kierunki możliwych sposobów implementacji mapy, ale nie jestem DBA, więc nie jestem pewien, czy są jakieś plusy i minusy, których mi brakowało.
W celu wyjaśnienia abstrakcji rozważ trzy grupy różnych danych użytkowników: profesorowie, administracja, studenci (nie, to nie zadanie domowe. Obiecuj!)
Mapowanie 1
(professor_id, admin_id i student_id są kluczami obcymi do odpowiednich tabel)
| mailing_id (KEY) | professor_id | admin_id | student_id |
-------------------------------------------------------
| 1001 | NULL | 87 | NULL |
| 1002 | 123 | NULL | NULL |
| 1003 | NULL | NULL | 123 |
Podejście +/- do tego podejścia wydaje się dość duże wady:
- Dwa „zmarnowane” pola w rzędzie
- Narusza 2NF
- Podatne na wstawienie / aktualizację anomalii (wiersz z ustawionym tylko wartością 0-1 NULL, np.)
Zalety nie są jednak pozbawione własnych zalet:
- Mapowanie można wykonać za pomocą pojedynczego wyszukiwania
- Łatwo określ dane „źródłowe” dla danego użytkownika na podstawie id_poczty
Prawdę mówiąc, w moich jelitach wcale nie podoba mi się ten pomysł.
Mapowanie 2
(załóżmy, że MSG_ * to zdefiniowane stałe, typy wyliczeniowe lub inny odpowiedni identyfikator)
| mailing_id (KEY) | user_type (UNIQUE1) | internal_id (UNIQUE2)|
------------------------------------------------------------------
| 1001 | MSG_ADMIN | 87 |
| 1002 | MSG_PROF | 123 |
| 1003 | MSG_STUDENT | 123 |
Dzięki tej konfiguracji i unikalnemu indeksowi złożonemu {typ_użytkownika, identyfikator_wewnętrzny} rzeczy stają się znacznie czystsze, utrzymywana jest 3NF, a kod aplikacji nie musi sprawdzać anomalii I / U.
Wadą jest jednak niewielka utrata przejrzystości przy określaniu tabel źródłowych użytkownika, które muszą być obsługiwane poza DB, co w zasadzie sprowadza się do mapowania na poziomie aplikacji wartości user_type na tabele. W tej chwili (raczej mocno) pochylam się w kierunku tego drugiego mapowania, ponieważ wada jest raczej niewielka.
ALE jestem boleśnie świadomy własnych ograniczeń i jestem pewien, że prawdopodobnie przegapiłem zalety lub przeszkody w obu kierunkach, więc zwracam się do mądrzejszych umysłów niż moich.
źródło
Odpowiedzi:
Twój drugi pomysł jest właściwy. Takie podejście umożliwia wykonanie wszystkich mapowań, które należy wykonać, aby zintegrować trzy kolidujące ze sobą przestrzenie klawiszy.
Co ważne, pozwala bazie danych narzucić większość spójności, którą trzeba mieć przy użyciu ograniczeń deklaratywnych .
Masz już więcej kodu, niż chcesz, więc nie dodawaj więcej kodu, niż jest to absolutnie konieczne, aby zachować spójność zintegrowanej listy kluczy. Pozwól, aby silnik bazy danych zrobił to, co został zbudowany.
„Problematyczne dziecko”, które powoduje dyskomfort w Mapowaniu 2, to
USER_TYPE
kolumna. Ta kolumna jest ważna, ponieważ potrzebujesz jej, abyINTERNAL_ID
wyświetlała się tylko raz dla każdego typu użytkownika. Jedyny raz, kiedy potrzebujesz kodu, który jest nawet świadomy,USER_TYPE
to kod, który wstawia i usuwa z tabeli odwzorowań. Można to dość dobrze zlokalizować. Zakładam, że utworzysz pojedynczy punkt w kodzie, w którym utrzymywana będzie zawartość tabeli mapowania. Dodatkowa kolumna w tym jednym miejscu, w którym zapisywane są dane, nie jest wielkim problemem. To, czego naprawdę chcesz uniknąć, to dodawanie dodatkowej kolumny wszędzie tam, gdzie czytane są dane .Kod w twoich podaplikacjach, które muszą korzystać z mapowania, może być błogo ignorantem, po
USER_TYPE
prostu dając każdej pod-aplikacji widok, który filtruje mapowania do jednego typu użytkownika specyficznego dla aplikacji.źródło
Z doświadczenia zalecam, aby wybierać spójność zamiast elegancji lub „najlepszych praktyk”. To znaczy, aby dopasować się do istniejącego projektu i iść z TRZYMI tabelami mailingowymi (po jednej dla każdej roli) o prostej
mailing_id, user_id
strukturze pola.Jest nieelegancki, ale ma kilka zalet ...
Jestem pewien, że wielu innych nie zgodzi się z tym podejściem, ale głównym celem normalizacji i najlepszych praktyk jest uczynienie kodu bardziej spójnym, aby łatwiej było śledzić i debugować ... i oczywiście doprowadzenie całej bazy kodu do zera prawdopodobnie nie jest możliwe.
źródło