Dlaczego ograniczenia są stosowane w bazie danych, a nie w kodzie?

21

Dlaczego ograniczenia są stosowane w bazie danych? Czy wstawienie go do kodu nie będzie bardziej elastyczne?

Czytam książkę dla początkujących na temat wdrażania baz danych, więc pytam o to jako początkujący. Powiedzmy, że zaprojektowałem bazę danych, w tym ten model encji:

 entity type    |   sub-types
----------------+--------------------------------------------
   Person       |   Employee, Student,       ...
   Student      |   Graduate, Undergraduate, ...
   Employee     |   Teacher,  Administrator, ...

Obecne ograniczenia:

  1. Zarejestrowaną osobą w systemie może być tylko Student lub Pracownik.
  2. Istota osobowa wymaga unikalności numeru społecznego, który, jak zakładamy, każda osoba posiada tylko jeden unikalny numer (czyli wystarczająco dobry klucz podstawowy). (patrz # 1)

Później decydujemy się usunąć numer 1: jeśli któregoś dnia kolegium zdecyduje, że Teacher( Employeepodtyp) może być również Student, biorąc udział w kursach w wolnym czasie, znacznie trudniej jest zmienić projekt bazy danych, który mógłby mieć tysiące, miliony, miliardy, zyliony wpisów, a nie tylko zmiana logiki w kodzie: tylko część, która nie pozwalała na rejestrację osoby jako ucznia i pracownika.

(To bardzo nieprawdopodobne, ale nie mogę teraz myśleć o niczym innym. Najwyraźniej jest to możliwe).

Dlaczego dbamy o reguły biznesowe w projektowaniu baz danych, a nie w kodzie?

# 1: Notatka 7 lat później, przykład z prawdziwego życia:
Widziałem rząd, w którym z powodu błędu wydano numery SSN: wiele osób, ten sam numer SSN. Projektanci oryginalnego DB zdecydowanie popełniali błąd, nie stosując tego ograniczenia unikatowości w bazie danych. (a później błąd w oryginalnej aplikacji? wiele aplikacji korzystających ze wspólnej bazy danych i nie zgadzających się, gdzie umieścić, sprawdzić i egzekwować ograniczenie? ...).
Ten błąd będzie nadal działał w systemie, a cały opracowany system będzie bazował na bazie danych tego oryginalnego systemu przez wiele lat. Czytając tutaj odpowiedzi, nauczyłem się stosować wszystkie ograniczenia, tak wiele z nich, jak to możliwe, mądrze (nie na ślepo) w bazie danych, aby reprezentować prawdziwy świat fizyczny tak dobrze, jak potrafię.

hkoosha
źródło
2
Przeważnie dbamy o egzekwowanie reguł biznesowych i jaki jest najlepszy sposób.
ypercubeᵀᴹ
3
W rzeczywistości prezentujesz bardzo zły przykład tego, do czego są stosowane ograniczenia, ponieważ elastyczność twoich jednostek i możliwość rozbudowy bazy danych są w większości określone przez normalizację. Powiedziawszy to, ograniczenia są ostatecznym zabezpieczeniem przed wszelkimi uszkodzonymi danymi, które kiedykolwiek dostaną się do bazy danych, nawet jeśli aplikacja jest uszkodzona, nawet jeśli nowa aplikacja zostanie opracowana, nawet jeśli zostanie dodane zewnętrzne API, nawet jeśli ktoś bezpośrednio edytuje DB. Ograniczenia chronią bazę danych, poza tym logika biznesowa będzie musiała również robić swoje, zanim spróbuje uzyskać dostęp do bazy danych.
Niels Keurentjes
3
Właściwie jako absolwent uważany jestem zarówno za Studenta, Pracownika, jak i Nauczyciela. Więc twój przykład nie jest tak nieprawdopodobny.
Winston Ewert
4
Nigdy nie należy opierać projektu bazy danych na obiektach w aplikacji. Zwykle zaprojektowałbyś to jako osobę, a następnie miałeś powiązany stół, aby zdefiniować role osób. Wtedy problem nie pojawia się, gdy masz ustawiony stół dla ról, więc ludzie mogą mieć wiele ról. Jeśli chcesz mieć tylko jedną rolę osoby, ogranicz tabelę, aby unikalny był identyfikator peopleID. Kiedy chcesz to zmienić, usuń ograniczenie.
HLGEM
Obiekt <-> Mapowanie relacyjne jest sztuką.
Thorbjørn Ravn Andersen

Odpowiedzi:

34

Niektóre ograniczenia najlepiej egzekwować w bazie danych, a niektóre najlepiej w aplikacji.

Zazwyczaj istnieją ograniczenia, które najlepiej egzekwować w bazie danych, ponieważ mają one fundamentalne znaczenie dla struktury modelu danych, takie jak ograniczenie klucza obcego w celu zapewnienia, że ​​produkt jest ważny category_id.

Ograniczenia, które są egzekwowane w aplikacji, mogą nie być fundamentalne dla modelu danych, tak jak wszystkie produkty FooBar muszą być niebieskie - ale później ktoś może zdecydować, że FooBars mogą być również żółte. Jest to logika aplikacji, która tak naprawdę nie musi znajdować się w bazie danych, chociaż można utworzyć osobną colourstabelę, a baza danych może wymagać, aby produkt odwoływał się do poprawnego wpisu z tej tabeli. ALE decyzja, że ​​jedyny wpis coloursma wartość blue, nadal pochodziłaby spoza bazy danych.

Zastanów się, co by się stało, gdybyś nie miał żadnych ograniczeń w bazie danych i wymagał, aby wszystkie były egzekwowane w aplikacji. Co by się stało, gdybyś miał więcej niż jedną aplikację, która musiała pracować z danymi? Jak wyglądałyby Twoje dane, gdyby różne aplikacje decydowały się na inne wymuszanie ograniczeń?

Twój przykład pokazuje sytuację, w której bardziej korzystne byłoby ograniczenie w aplikacji niż w bazie danych, ale być może istniał podstawowy problem z tym, że początkowy model danych był zbyt restrykcyjny i nieelastyczny?

FrustratedWithFormsDesigner
źródło
Zatem zgodnie z tą odpowiedzią reguła <a person może istnieć tylko w tabeli podtypu Studenta lub tylko w tabeli podtypu Pracowników> powinna być zastosowana w kodzie, a baza danych ma <Podtyp Studenta / Pracownika musi być poprawny osoba> ograniczenie. Czy mam rację? (To był przykład książki). dzięki.
hkoosha
2
@loolooyyyy: Tak, myślę, że to prawda. Jeśli baza danych wymusza pierwszą zasadę (że dana osoba może być tylko studentem lub pracownikiem), to opisana przez ciebie sytuacja (w której pracownik chce się zapisać na zajęcia) jest niemożliwa, ponieważ: osoba nie może być jednocześnie obiema osobami i nie jest możliwe jest nawet utworzenie drugiego rekordu „osobowego”, ponieważ nie mogą oni udostępniać numerów ubezpieczenia społecznego, które są prawdopodobnie wydawane przez osoby trzecie (takie jak rząd). Oczywiście ten zbyt restrykcyjny model danych może działać w niektórych przypadkach ...
FrustratedWithFormsDesigner
2
@loolooyyyy: Innym sposobem na użycie oryginalnego modelu danych i nadal pozwalanie nauczycielom na uczenie się może być wywołanie kolejnej tabeli, teachers_as_studentsktóra jest kolejnym podtypem Studentsi ma nowy klucz obcy odnoszący się do niego Teachers, oraz wygenerowany przez system klucz podstawowy zamiast Społeczności Numer zabezpieczający. W ten sposób „uczeń” jest aliasem dla nauczyciela, więc nauczyciel może się zarejestrować, aby wziąć udział w zajęciach. Trudno powiedzieć na pewno, jak dobrze by to działało, nie widząc całego modelu danych.
FrustratedWithFormsDesigner
2
Głosowałem za tym. Nie ma czasu, kiedy ograniczenie jest najlepiej egzekwowane tylko w aplikacji . Ton tej odpowiedzi jest niewłaściwie ważony.
Evan Carroll
3
@FrustratedWithFormsDesigner z pewnością jest to potomek plakatu dla ograniczenia klucza obcego. Załóżmy, że masz trzech klientów w różnych wersjach / wersjach punktu dostępowego db. Co zrobisz, gdy przestaniesz wysyłać ten produkt na czerwono? Gdzie zamierzasz przechowywać listę możliwych kombinacji kolorów? Wskazówka: Mam dla ciebie scentralizowane miejsce. A jeśli utworzysz tabelę color_products, i colorprawdopodobnie będziesz w stanie łatwiej tworzyć dodatkowe listy rozwijane - większość programów ładujących IDE / schematów, obsługuje następujące klawisze.
Evan Carroll
35

Bo:

  1. Chcę, aby wszystkie dane w bazie danych podlegały tym samym ograniczeniom, a nie tylko nowe dane podlegały ograniczeniom w wersji kodu, która jest dziś uruchomiona.
  2. Chcę ograniczeń deklaratywnych, a nie programowych.
  3. Dane w bazie danych często przeżywają kod napisany w celu współdziałania z nim dzisiaj. A te dane - nie kod - są zasobem organizacji.
  4. Mój kod staje się znacznie prostszy, gdy wiem, że wszystkie dane podlegają rygorystycznym ograniczeniom. Nie muszę już rozważać specjalnych przypadków, o których wiem, że baza danych gwarantuje, że jest to niemożliwe.

Tylko kilka ważnych dla mnie powodów.

Colin 't Hart
źródło
4
Częściowo związane z (1) i (3): błędy w kodzie aplikacji można naprawić, błędy w danych są często nieodwracalne.
mu jest za krótki
17

Dane prawdopodobnie długo przeżyją kod aplikacji. Jeśli reguła ma kluczowe znaczenie dla danych, które są użyteczne w czasie (jak ograniczenia klucza obcego, które pomagają zachować integralność danych), musi znajdować się w bazie danych. W przeciwnym razie istnieje ryzyko utraty ograniczenia w nowej aplikacji, która trafia do bazy danych. Wiele aplikacji nie tylko uderza w bazy danych (w tym niektóre, które mogą nie zdawać sobie sprawy, że istnieje ważna reguła danych), ale niektóre z nich, takie jak import danych lub aplikacje raportujące, mogą nie być w stanie korzystać z warstwy danych skonfigurowanej w głównej aplikacji do wprowadzania danych. Szczerze mówiąc, w moim doświadczeniu prawdopodobieństwo wystąpienia błędu w ograniczeniu jest znacznie wyższe w kodzie aplikacji.

Moim osobistym zdaniem (w oparciu o ponad 30 lat pracy z danymi i doświadczeniem w setkach różnych baz danych wykorzystywanych do wielu różnych celów) każdy, kto nie umieści ograniczeń w bazie danych, do której należą, ostatecznie będzie miał słabe dane. Czasami złe dane do tego stopnia, że ​​nie nadają się do użytku. Jest to szczególnie ważne, gdy masz dane finansowe / regulacyjne, które muszą spełniać określone kryteria badania.

HLGEM
źródło
17

Większość referencyjnych ograniczeń integralności, które są wdrażane poza bazą danych, można pokonać, więc jeśli chcesz, aby Twoje dane miały gwarantowaną integralność przez cały czas, musisz zastosować ograniczenia w bazie danych. Full stop, to wszystko.

Zazwyczaj ograniczenia na poziomie aplikacji są eliminowane przez mechanizm spójności odczytu bazy danych, dzięki któremu sesje nie mogą przeglądać danych innych sesji, dopóki nie zostaną zatwierdzone.

Na przykład dwie sesje mogą próbować wstawić tę samą wartość do kolumny, która ma być unikalna. Mogą one zarówno check jednocześnie , że wartość nie istnieje, można wstawić zarówno ich wartości, a może obie zobowiązują. Unikalne ograniczenie zaimplementowane w bazie danych nie pozwoli na to.

Nawiasem mówiąc, nie jest to nieznane projektantom języka aplikacji. Przeczytaj rozdział 3.10 o wyjątkowości w przewodnikach Ruby on Rails: Aktywne sprawdzanie poprawności rekordów i callbacki

Ten pomocnik sprawdza, czy wartość atrybutu jest unikalna tuż przed zapisaniem obiektu. Nie tworzy ograniczenia unikatowości w bazie danych, więc może się zdarzyć, że dwa różne połączenia z bazą danych utworzą dwa rekordy o tej samej wartości dla kolumny, która ma być unikalna. Aby tego uniknąć, musisz utworzyć unikalny indeks w bazie danych.

David Aldridge
źródło
16

Korzyści wynikające z ograniczeń wymuszonych przez bazę danych:

Prostota - Zadeklarowanie ograniczenia jest znacznie prostsze niż zadeklarowanie ograniczenia i napisanie kodu, który wymusi tę deklarację.

Dokładność - kod, który nie napisałeś, nigdy nie będzie zawierał błędu, który sam stworzyłeś. Dostawcy baz danych spędzają czas, upewniając się, że kod ograniczenia jest dokładny, więc nie musisz.

Szybkość - Twoja aplikacja nigdy nie może mieć więcej dystrybucji niż baza danych, na której jest oparta. Dostawcy baz danych spędzają czas, upewniając się, że kod ograniczenia jest wydajny, więc nie musisz. Sama baza danych ma również szybszy dostęp do danych, niż aplikacja mogłaby kiedykolwiek mieć, bez względu na to, jak wydajna.

Ponowne użycie - możesz zacząć od jednej aplikacji na jednej platformie, ale może tak nie być. Co zrobić, jeśli chcesz uzyskać dostęp do danych z innego systemu operacyjnego, innego sprzętu lub interfejsu głosowego? Dzięki ograniczeniom w bazie danych kod ten nigdy nie musi być przepisywany na nową platformę i nigdy nie musi być debugowany w celu zapewnienia dokładności ani profilowany pod kątem szybkości.

Kompletność - aplikacje wymuszają ograniczenia, gdy dane są wprowadzane do bazy danych i wymagałyby dodatkowego wysiłku, aby zweryfikować dokładność starszych danych lub manipulować danymi znajdującymi się już w bazie danych.

Długowieczność - Twoja platforma bazy danych prawdopodobnie przeżyje określoną aplikację.

Leigh Riffel
źródło
11

Dlaczego na serwerze stosowane są ograniczenia? Ponieważ nie możesz zmusić złych do korzystania z twojego klienta.

Aby to wyjaśnić, jeśli przetwarzasz reguły biznesowe tylko w aplikacji klienckiej, wówczas osoba korzystająca z innego narzędzia może połączyć się z serwerem bazy danych i robić, co tylko zechce, bez ograniczeń wynikających z reguł biznesowych i kontroli integralności. Bardzo trudno jest uniemożliwić komukolwiek korzystanie z dowolnego narzędzia w dowolnym miejscu w sieci.

Jeśli wykonasz sprawdzanie integralności na serwerze bazy danych, każda próba dostępu do danych, niezależnie od narzędzia, będzie ograniczona twoimi regułami.

Greenstone Walker
źródło
10

Kilka świetnych odpowiedzi tutaj i na ryzyko powtórzenia innych myśli:

  • SSN jest nie koniecznie unikatowa. Do cholery, SSN nie zawsze jest znany, aw niektórych przypadkach nie istnieje (jeszcze). SSN mogą być ponownie wykorzystane i nie wszyscy pracownicy lub studenci mogą mieć SSN. Jest to kwestia poboczna w stosunku do pytania, ale pokazuje, że bez względu na to, gdzie egzekwujesz ograniczenia, musisz dość dokładnie zrozumieć model danych i domenę, aby podejmować decyzje dotyczące reguł biznesowych.
  • Osobiście wolę, aby ograniczenia były jak najbardziej zbliżone do danych. Bardzo prosty powód jest taki, że nie wszyscy użyją kodu aplikacji do zmiany danych w bazie danych. Jeśli egzekwujesz reguły biznesowe na poziomie aplikacji, a ja uruchamiam UPDATEinstrukcję bezpośrednio w bazie danych, w jaki sposób Twoja aplikacja zapobiega nieprawidłowej zmianie? Innym problemem związanym z regułami biznesowymi w aplikacji jest to, że ponowna kompilacja / ponowne wdrożenie może być trudne, szczególnie w przypadku aplikacji rozproszonych, w których możliwe jest, że nie wszyscy otrzymają aktualizację w tym samym czasie. I wreszcie, zmiana reguł biznesowych w aplikacji nie ma absolutnie nic wspólnego z danymi, które już istnieją, co narusza nowe reguły - jeśli dodasz nowe ograniczenie do danych, musisz je naprawić.
  • Możesz uzasadnić wiele zbędnych kontroli na różnych poziomach. Wszystko zależy od elastyczności metod wdrażania, prawdopodobieństwa zmiany i trudności w synchronizacji zmiany reguł biznesowych w bazie danych i innych warstwach. Przekonującym argumentem za powtarzaniem kontroli w warstwie aplikacji jest to, że można potencjalnie zapobiec powrotom w obie strony do bazy danych tylko w przypadku niepowodzenia ograniczenia (w zależności od charakteru ograniczenia i tego, czy opiera się on na istniejących danych). Ale gdybym musiał wybrać jeden lub drugi, umieściłbym go w bazie danych z powyższych powodów.

W przypadku, gdy wyraźnie wspominasz, że nagle zezwalasz na coś, co wcześniej było niedozwolone, nie jest to tak naprawdę problemem - usuwasz wszelkie wymuszone ograniczenia, niezależnie od tego, gdzie to istnieje. W przeciwnym przypadku, gdy nagle nauczycielom nie wolno już być uczniami, potencjalnie masz do wyczyszczenia mnóstwo danych, bez względu na to, gdzie wcześniej istniało ograniczenie.

Aaron Bertrand
źródło
9
  1. Baza danych może skutecznie sprawdzać ograniczenia. Lepsze niż kod.

  2. Ograniczenia integralności pomagają bazie danych znaleźć skuteczny plan wykonania

  3. Aplikacja widzi spójny widok, dlatego nie może zagwarantować wyjątkowości. Podczas gdy baza danych może również zobaczyć dane niezaangażowane.

ibre5041
źródło
8

Krótka odpowiedź ... w celu zachowania integralności danych (tj. Dokładności i ważności).

Wyjątek ...
Jeśli baza danych przechowuje dane jednej aplikacji dla jednego użytkownika, na przykład w większości baz danych Sqlite, może nie wymagać ograniczeń. W rzeczywistości zazwyczaj tak nie jest, aby czas dostępu był tak szybki, że nie można go zmierzyć.

Do wszystkiego innego ...
Bazy danych zawsze obsługują dwa wzorce, które nazywam edytorami i użytkownikami .

Redaktorzy najczęściej umieszczają dane w bazie danych i pobierają dane jeden lub niewielką liczbę rekordów jednocześnie. Ich najważniejsze obawy to szybki, dokładny dostęp do wszystkich powiązanych danych oraz szybkie i niezawodne przechowywanie ich zmian.

Użytkownicy w większości pobierają dane, a najbardziej zależy im na szybkim dostępie do niewątpliwie dokładnych informacji. Często potrzebują różnych zliczeń, agregacji i list, które kiedyś były generowane w tych kultowych grubych na stosy stosach wydruków z zielonego papieru, ale zwykle trafiają dziś na strony internetowe.

Projekty tworzenia baz danych są prawie zawsze uruchamiane na żądanie użytkowników , ale projekt opiera się na potrzebach redaktorów dotyczących wprowadzania danych i nagrywania na raz . W związku z tym niedoświadczeni programiści często reagują na pilną potrzebę szybkości (przede wszystkim rozwoju ), nie nakładając ograniczeń w bazie danych.

Jeśli jedna i tylko jedna aplikacja będzie kiedykolwiek używana do wprowadzania zmian w danych przez cały okres życia bazy danych, a ta aplikacja jest rozwijana przez jedną lub niewielką liczbę dobrze skoordynowanych osób, uzasadnione może być poleganie na aplikacja do zapewnienia integralności danych.

Jednak o ile udajemy, że możemy przewidzieć przyszłość, nie możemy.

Wysiłek stworzenia bazy danych jest zbyt cenny, aby ją kiedykolwiek wyrzucić. Baza danych, podobnie jak dom, będzie wielokrotnie rozbudowywana, zmieniana i odnawiana. Nawet po całkowitym zastąpieniu wszystkie dane zostaną przeniesione do nowej bazy danych, zachowując jednocześnie wszystkie stare reguły biznesowe i relacje.

Ograniczenia implementują te reguły i relacje w zwięzłej, deklaratywnej formie w samym silniku bazy danych, gdzie są łatwo dostępne. Bez nich kolejni programiści musieliby przeglądać programy aplikacyjne, aby poddać inżynierii wstecznej te reguły. Powodzenia!

Nawiasem mówiąc, właśnie to muszą zrobić programiści COBOL na komputerach mainframe, ponieważ te ogromne bazy danych były często tworzone, zanim mieliśmy relacyjne mechanizmy i ograniczenia. Nawet po migracji do nowoczesnego systemu, takiego jak DB2 IBM, ograniczenia czasami nie są w pełni zaimplementowane, ponieważ logika starych reguł, zawartych być może w serii programów wsadowych COBOL, może być tak skomplikowana, że ​​nie można ich przekonwertować. Zamiast tego można użyć zautomatyzowanych narzędzi do konwersji starego COBOL-a na nowszą wersję z interfejsami do nowego silnika relacyjnego i przy niewielkich poprawkach integralność danych zostaje zachowana ... do momentu napisania nowej aplikacji, która subtelnie psuje wszystko i firma zostaje przeniesiona do sądu, powiedzmy, wykluczając tysiące właścicieli domów, których nie powinni mieć.

DocSalvager
źródło
7

Oprócz innych komentarzy ...

Jeśli / kiedy masz bazę danych, w której dowolna tabela może być aktualizowana przez jedną lub więcej aplikacji lub ścieżek kodu, wówczas umieszczenie odpowiednich ograniczeń w bazie danych oznacza, że ​​twoje aplikacje nie będą duplikowały „tego samego” kodu ograniczenia. Przynosi to korzyść, upraszczając konserwację (zmniejszając liczbę miejsc do zmiany w przypadku zmiany modelu danych) i zapewnia konsekwentne stosowanie ograniczeń bez względu na aktualizację danych przez aplikację.

gsiems
źródło
5

Osobiście uważam, że łatwiej jest tworzyć i modyfikować ograniczenia niż na przykład wyzwalacze, które mogłyby być jednym ze sposobów egzekwowania reguł biznesowych za pomocą kodu źródłowego.

Również wyzwalacze są mniej prawdopodobne, aby były przenośne, ponieważ zwykle są pisane w językach określonych przez dostawcę, takich jak PL / SQL.

Ale jeśli ograniczenia nie spełniają Twoich potrzeb, zawsze możesz użyć wyzwalaczy w celu egzekwowania reguł biznesowych.

Perła
źródło
5
Wyzwalacze również nie gwarantują integralności z powodu problemów z spójnością odczytu.
David Aldridge
3

Zawsze powinny być najpierw stosowane w bazie danych, ponieważ

  1. Baza danych zapewnia integralność między różnymi klientami. Możesz mieć różnych klientów na różnych platformach uzyskujących dostęp do bazy danych. Ograniczenia w bazie danych nie ryzykują problemów z integralnością podczas tworzenia nowego klienta. To oszczędza Ci konieczności sprawdzania swoich ograniczeń w przypadku przepisania lub dodatkowego punktu dostępu.
  2. Baza danych ma DSL do tworzenia ograniczeń: SQL DDL!
  3. Baza danych zapewnia dostęp do tych ograniczeń w katalogach systemowych, dzięki czemu właściwy ORM lub „moduł ładujący schematy” może odczytać te ograniczenia i wprowadzić je do aplikacji. Na przykład, jeśli baza danych określa, że ​​masz varchar(5)typ, istnieje duża szansa, że ​​znajdziesz schemat ładujący ORM dla określonego języka, który mapuje typ języka na typ schematu i zestawia własne ograniczenie wielkości. DBIx for Perl is one such schema loader; tutaj jest inny dla Entity Framework . Możliwości tych programów ładujących są różne, ale wszystko, co mogą zapewnić, to dobry początek, aby zapewnić integralność aplikacji bez podróży do bazy danych.
Evan Carroll
źródło