Dlaczego nie powinniśmy dopuszczać wartości NULL?

125

Pamiętam, jak czytałem ten jeden artykuł na temat projektowania baz danych i pamiętam również, że powinieneś mieć właściwości pola NOT NULL. Nie pamiętam jednak, dlaczego tak było.

Mogę tylko myśleć o tym, że jako twórca aplikacji nie musiałbyś testować NULL i możliwej nieistniejącej wartości danych (na przykład pusty ciąg znaków dla łańcuchów).

Ale co robisz w przypadku dat, godziny i godziny (SQL Server 2008)? Będziesz musiał skorzystać z jakiejś historycznej lub oddolnej daty.

Jakieś pomysły na ten temat?

Thomas Stringer
źródło
4
Ta odpowiedź zawiera informacje na temat korzystania z NULL dba.stackexchange.com/questions/5176/…
Derek Downey
10
Naprawdę? Dlaczego RDBMS pozwala nam w ogóle używać NULL, jeśli nie powinniśmy ich używać? Nie ma nic złego w NULL, o ile wiesz, jak sobie z nimi poradzić.
Fr0zenFyr
3
Czy było to modelowanie danych BI? Zasadniczo nie powinieneś zezwalać na wartości zerowe w tabelach ... w przeciwnym razie wartości zerowe są Twoimi przyjaciółmi, jeśli są właściwie używane. =)
sam yi
2
@ Fr0zenFyr, tylko dlatego, że RDBMS pozwala nam coś zrobić, niekoniecznie jest to dobry pomysł. Nic nie zmusza nas do zadeklarowania klucza podstawowego lub unikalnego klucza w tabeli, ale z kilkoma wyjątkami tak robimy.
Lennart
3
Myślę, że pełne podejście do tego tematu musiałoby odnosić się do pierwotnego wymogu Codda, że ​​RDBMS musi mieć systematyczny sposób leczenia brakujących danych. W prawdziwym świecie zdarzają się sytuacje, w których tworzona jest lokalizacja danych, ale nie ma w niej danych. Architekt danych musi odpowiedzieć na to pytanie, niezależnie od tego, czy dotyczy to projektowania baz danych, programowania aplikacji, czy obu. SQL NULL jest mniej niż doskonały w spełnianiu tego wymagania, ale jest lepszy niż nic.
Walter Mitty

Odpowiedzi:

229

Myślę, że pytanie jest źle sformułowane, ponieważ sformułowanie sugeruje, że już zdecydowałeś, że wartości NULL są złe. Być może miałeś na myśli „Czy powinniśmy dopuszczać wartości NULL?”

Tak czy inaczej, oto moje zdanie na ten temat: Myślę, że wartości NULL są dobre. Gdy zaczniesz zapobiegać wartościom NULL tylko dlatego, że „wartości NULL są złe” lub „wartości NULL są trudne”, zaczniesz tworzyć dane. Na przykład, co jeśli nie znasz mojej daty urodzenia? Co zamierzasz umieścić w kolumnie, dopóki się nie dowiesz? Jeśli jesteś kimś w rodzaju wielu przeciwników NULL, wejdziesz do 1900-01-01. Teraz zostanę umieszczony na oddziale geriatrycznym i prawdopodobnie otrzymam telefon z mojej lokalnej stacji prasowej gratulując mi długiego życia, prosząc mnie o sekrety tak długiego życia itp.

Jeśli można wprowadzić wiersz, w którym możliwe jest, że nie znasz wartości kolumny, myślę, że NULL ma o wiele większy sens niż wybranie jakiejkolwiek arbitralnej wartości tokena reprezentującej fakt, że jest nieznana - wartość, którą inni będą muszę już wiedzieć, inżynierii wstecznej lub poprosić, aby dowiedzieć się, co to znaczy.

Jest jednak równowaga - nie każda kolumna w twoim modelu danych powinna mieć wartość zerową. Często w formularzu są pola opcjonalne lub informacje, które w przeciwnym razie nie są gromadzone w momencie tworzenia wiersza. Ale to nie znaczy, że możesz odroczyć zapełnianie wszystkich danych. :-)

Zdolność do używania NULL może być ograniczona przez kluczowe wymagania w prawdziwym życiu. Na przykład w dziedzinie medycyny wiedza o tym, dlaczego wartość jest nieznana , może być sprawą życia lub śmierci . Czy częstość akcji serca jest NULL, ponieważ nie było tętna lub dlatego, że jeszcze go nie mierzyliśmy? W takim przypadku, czy możemy wstawić NULL w kolumnie tętna i mieć notatki lub inną kolumnę z NULL-z powodu powodu?

Nie bój się wartości NULL, ale bądź gotów nauczyć się lub dyktować, kiedy i gdzie powinny być używane, a kiedy i gdzie nie powinny.

Aaron Bertrand
źródło
3
„jakaś dowolna wartość tokena reprezentująca fakt, że nie jest znana” jest to znane jako wartość wartownika
Alexander
4
Ale co powstrzymuje cię przed utworzeniem osobnej tabeli, w birth_datektórej przechowujesz daty urodzenia? Jeśli data urodzenia jest nieznana, po prostu nie wstawiaj daty urodzenia birth_date. Nulls to katastrofa.
Eldar Agalarov
6
@EldarAgalarov To brzmi jak rozumowanie Trumpa („katastrofa” dlaczego? Jak? Dla kogo? Twoja opinia, że ​​coś jest „katastrofą”, nie czyni tego). W każdym razie data urodzenia to tylko jeden przykład. Jeśli masz personel, członków lub klientów, którzy mają 15 potencjalnie pustych kolumn, czy zamierzasz utworzyć 15 tabel pomocniczych? Co jeśli masz 50? Co jeśli twoja tabela faktów DW ma 500? Utrzymanie dużych, przerażających wartości NULL w bazie danych staje się 10-krotnie większe niż jakakolwiek „katastrofa”, której się boisz ...
Aaron Bertrand
3
@AaronBertrand, jeśli twoja tabela ma 15 potencjalnie zerowalnych kolumn, pachnie naprawdę źle ^^ Nie, że ogromna liczba kolumn jest z natury zła, ale może to wskazywać na zły projekt LUB wymaganą denormalizację. Ale to rodzi pytania.
programaths
2
@Wildcard Więc nigdy nie widziałeś, żeby ludzie zapisywali dane, 1900-01-01aby uniknąć NULL wartości daty / godziny? Ok więc. Również NULL = nieznany i nieznany = fałszywy. Nie jestem pewien, jakie problemy mogą powodować inne niż ludzie, którzy nie rodzą się, wiedząc o tym (tak jakby nie rodzili się, wiedząc wiele rzeczy związanych ze złożonym RDBMS). Znów machając rękami i mówiąc „Problem! Katastrofa!” tak nie robi.
Aaron Bertrand
57

Ustalone powody to:

  • NULL nie jest wartością, a zatem nie ma wewnętrznego typu danych. Wartości NULL wymagają specjalnej obsługi w każdym miejscu, gdy kod, który w innym przypadku opiera się na rzeczywistych typach, może również otrzymać niepoprawny NULL.

  • NULL łamie logikę dwóch wartości (znana prawda lub fałsz) i wymaga logiki trzech wartości. Jest to o wiele bardziej skomplikowane nawet w przypadku prawidłowego wdrożenia i jest z pewnością słabo zrozumiane przez większość DBA i prawie wszystkie inne niż DBA. W rezultacie pozytywnie zachęca do wielu subtelnych błędów w aplikacji.

  • Znaczenie semantyczne dowolnego określonego NULL pozostawia się aplikacji , w przeciwieństwie do rzeczywistych wartości.

    Semantyka, taka jak „nie dotyczy” i „nieznany” i „wartownik”, są powszechne, są też inne. Są często używane jednocześnie w tej samej bazie danych, nawet w tej samej relacji; i są oczywiście niewytłumaczalne, nierozróżnialne i niekompatybilne .

  • Nie są one konieczne do relacyjnych baz danych , jak argumentowano w „Jak radzić sobie z brakującymi informacjami bez wartości zerowych” . Dalsza normalizacja jest oczywistym pierwszym krokiem, aby spróbować pozbyć się tabeli NULL.

To nie znaczy, że NULL nigdy nie powinien być dozwolony. To nie twierdzą, że istnieje wiele dobrych powodów, aby uniemożliwić NULL gdziekolwiek to możliwe.

Co istotne, przemawia za tym, aby bardzo się starać - dzięki lepszemu projektowaniu schematów i lepszym silnikom baz danych, a nawet lepszym językom baz danych - aby umożliwić częstsze unikanie NULL.

Fabian Pascal odpowiada na szereg argumentów w „Nulls Nullified” .

duży nos
źródło
3
Twój link do „Jak radzić sobie z brakującymi informacjami bez wartości zerowych” pokazuje całkiem dobrze, dlaczego nie możemy obejść się bez wartości zerowych: Kilka sugestii byłoby niemożliwych do racjonalnego wdrożenia w głównych systemach RDBMS w ich obecnym stanie.
Jack Douglas
7
Jack: Racja, ale „obecne implementacje nie mogą tego zrobić” nie jest argumentem za status quo :-)
bignose
17
Czy to takie powiedzenie, że nie powinniśmy latać, ponieważ samoloty nie są idealne?
Aaron Bertrand
11
Nie, mówi się, że sprzedawcy powinni przestać powoływać się na usprawiedliwienia dla zer, które mogłyby być ważne czterdzieści lat temu, ale dawno przeżyły swój rozsądny okres przechowywania. Czasy wejścia / wyjścia nie są już rzędu 80 ms. Cykle pojedynczego procesora nie są już rzędu mikrosekund. Limity pamięci nie są już rzędu kilku megabajtów. W przeciwieństwie do czterdziestu lat temu, sprzętowe prędkości i pojemności potrzebne do pracy bez zer są teraz, a koszty nie są wygórowane. Mówi, że czas się ruszyć.
Erwin Smout,
2
Link „NULL zamieszanie” nie działa.
jpmc26
32

Nie zgadzam się, wartości zerowe są istotnym elementem projektowania baz danych. Alternatywą, jak również wspomniałeś, byłoby rozpowszechnianie znanych wartości reprezentujących brakujące lub nieznane. Problem polega na tym, że zero jest tak szeroko niezrozumiane, w wyniku czego jest stosowane niewłaściwie.

IIRC, Codd zasugerował, że obecna implementacja wartości zerowej (co oznacza brak / brak) może zostać ulepszona poprzez posiadanie dwóch pustych znaczników zamiast jednego, „nieobecny, ale odpowiedni” i „nieobecny i nie dotyczy”. Nie mogę przewidzieć, w jaki sposób projekty relacyjne zostałyby przez to ulepszone osobiście.

Mark Storey-Smith
źródło
2
Sugeruję posiadanie zdefiniowanego przez użytkownika zestawu różnych rodzajów nulli zdefiniowanej przez użytkownika logiki wielowartościowej, aby iść z nimi: p
Jack Douglas
13
To nie jedyne opcje. Wykluczasz alternatywę normalizacyjną: Zamiast kolumn, które mogą mieć wartość lub nie, użyj innej tabeli, która może, ale nie musi mieć odpowiadający wiersz dla pierwszej tabeli. Znaczenie obecności lub braku wiersza wynika z znaczenia tabel i nie ma specjalnej obudowy wartości NULL lub wartowników itp.
bignose
7
Obecność NULL nie wymaga specjalnych wartości ani wartości wartowników. To tylko symptomy tego, jak niektórzy ludzie decydują się radzić sobie z NULL.
Aaron Bertrand
Warto zauważyć, że '' różni się od null na PostgreSQL (choć nie Oracle), a zatem daje dwukrotny znacznik i można użyć 0 dla kolumn numerycznych. Problem z 0 polega jednak na tym, że nie działa on na klucze obce.
Chris Travers,
13

Zacznę od stwierdzenia, że ​​nie jestem DBA, jestem programistą na pamięć i utrzymuję i aktualizujemy nasze bazy danych w oparciu o nasze potrzeby. Biorąc to pod uwagę, miałem to samo pytanie z kilku powodów.

  1. Wartości zerowe utrudniają programowanie i podatność na błędy.
  2. Wartości zerowe sprawiają, że zapytania, procedury przechowywane i widoki są bardziej złożone i podatne na błędy.
  3. Wartości zerowe zajmują miejsce (? Bajtów na podstawie stałej długości kolumny lub 2 bajty na zmiennej długości kolumny).
  4. Wartości zerowe mogą i często wpływają na indeksowanie i matematykę.

Bardzo długo spędzam przesiewając w Internecie mnóstwo odpowiedzi, komentarzy, artykułów i porad. Nie trzeba dodawać, że większość informacji dotyczyła odpowiedzi @ AaronBertrand. Dlatego czułem potrzebę odpowiedzi na to pytanie.

Po pierwsze chcę ustawić coś prostego dla wszystkich przyszłych czytelników ... Wartości NULL reprezentują nieznane dane, NIE NIE wykorzystane dane. Jeśli masz tabelę pracowników z polem daty rozwiązania umowy. Wartość zerowa w dacie zakończenia wynika z tego, że jest to pole wymagane w przyszłości, które jest obecnie nieznane. Każdy pracownik, niezależnie od tego, czy jest aktywny czy zwalniany, w pewnym momencie będzie miał datę dodaną do tego pola. To jest moim zdaniem jedyny powód, dla którego pole Nullable.

Biorąc to pod uwagę, ta sama tabela pracowników najprawdopodobniej zawiera dane uwierzytelniające. W środowisku korporacyjnym pracownicy są umieszczani w bazie danych dla działu kadr i księgowości, ale nie zawsze mają lub nie potrzebują szczegółów uwierzytelnienia. Większość odpowiedzi prowadzi do przekonania, że ​​nieważne jest zerowanie tych pól lub w niektórych przypadkach utworzenie dla nich konta, ale nigdy nie wysyłanie im poświadczeń. Pierwszy z nich spowoduje, że Twój zespół programistów napisze kod, aby sprawdzić wartości NULL i odpowiednio sobie z nimi poradzić, a drugi stanowi ogromne zagrożenie bezpieczeństwa! Konta, które nigdy nie są jeszcze używane w systemie, zwiększają tylko liczbę możliwych punktów dostępu dla hakerów, a ponadto zajmują cenne miejsce w bazie danych dla czegoś, co nigdy nie jest używane.

Biorąc pod uwagę powyższe informacje, najlepszym sposobem na radzenie sobie z zerowalnymi danymi, które BĘDĄ być używane, jest dopuszczenie wartości zerowalnych. To smutne, ale prawdziwe, a twoi programiści będą cię za to nienawidzić. Drugi typ zerowalnych danych należy umieścić w powiązanej tabeli (IE: Konto, poświadczenia itp.) I mieć relację jeden do jednego. Umożliwia to istnienie użytkownika bez poświadczeń, chyba że są one potrzebne. Eliminuje to dodatkowe ryzyko bezpieczeństwa, cenne miejsce w bazie danych i zapewnia znacznie czystszą bazę danych.

Poniżej znajduje się bardzo uproszczona struktura tabeli pokazująca zarówno wymaganą zerowalną kolumnę, jak i relację jeden do jednego.

Nieznany związek dopuszczający wartości zerowe i jeden do jednego

Wiem, że jestem trochę spóźniony na imprezę od czasu, gdy zadano to pytanie lata temu, ale mam nadzieję, że pomoże to rzucić nieco światła na tę kwestię i jak najlepiej sobie z tym poradzić.

Nicholas Aguirre
źródło
2
Chciałbym tylko to zmienić, aby nie było TerminationDatew aktach pracownika, ale mieć tabelę, do TerminatedEmployeektórej pracownicy są przenoszeni (nie kopiowani) przez aplikację po ich rozwiązaniu. Oczywiście działa to dobrze z tabelą Konta, ponieważ nie będzie połączonego konta w TerminatedEmployeetabeli. Jeśli nadal potrzebujesz numerów telefonów, odwróciłbym klucze obce, aby pracownik i wypisane tabele pracowników miały identyfikator numeru telefonu zamiast na odwrót.
Programster
2
Mógłbym dosłownie mówić kilka dni o tym, dlaczego byłoby to złe. Nadmiarowe tabele, złe praktyki SQL, dzięki czemu programiści będą musieli szukać w dwóch miejscach danych pracowników, problemów z raportowaniem, problemów z bezpośrednimi URI dla pracownika, który nie istnieje (został przeniesiony), a lista jest długa i dalej. Zupełnie dobrze jest mieć NULLS dla pól, które kiedyś będą miały wartość, to kolejna historia, aby mieć pola, które nigdy się nie zapełniają i nigdy nie mają zastosowania. Szereg potencjalnych problemów i obejść tego problemu nie byłby wart drobnego problemu polegającego na sprawdzeniu wartości NULL na polu.
Nicholas Aguirre
1
Nie zgadzam się. Jedyne, co jest zbędne, to puste pole dla daty zakończenia, które może nigdy nie zostać wypełnione. Programiści muszą tylko szukać w odpowiedniej tabeli potrzebnych danych i mogą poprawić wydajność. Jeśli z jakiegoś powodu chcesz zarówno zwolnionych, jak i nieterminowych pracowników, rozwiązanie zostanie rozwiązane przez dołączenie, ale w 90% przypadków Twoja aplikacja prawdopodobnie będzie chciała jednego lub drugiego. Myślę, że układ, który określiłem, jest lepszy, ponieważ nie byłoby możliwe, aby pracownik miał datę rozwiązania umowy i aby nadal miał konto.
Programster
2
Nie powiedziałem nadmiarowych danych, powiedziałem nadmiarowe tabele. Ponadto wszelkie zmiany w tabelach pracowników muszą spływać do tabel zakończonych; powoduje to, że aplikacja jest podatna na błędy i znacznie utrudnia pracę programisty. Ponadto pole Data zakończenia zostanie wypełnione dla prawie wszystkich. Tworzenie drugiej identycznej struktury tabeli i przenoszenie danych jest marnotrawstwem i problematyczne. Nie należy uwzględniać testowania za każdym razem, aby upewnić się, że dane tabeli zostały przeniesione i wyczyszczone. Usunięcie danych ze tabeli jest złym zwyczajem, nawet jeśli tylko przeniesienie. Jeśli tak bardzo interesuje Cię jedno pole, że ...
Nicholas Aguirre
1
... który prawie zawsze zostanie wypełniony w czasie, a następnie utworzy z powrotem tabelę zakończoną relacją 1 do 1 z pracownikiem. Cały dzień pracuję z różnymi bazami danych, zarówno jako DBA, jak i jako programista, i cieszę się, że jeszcze nie spotkałem się z jedną z zaproponowanej przez Ciebie struktury. Zwłaszcza z punktu widzenia programisty pisanie i sprawdzanie błędów byłoby koszmarem, ponieważ nie wiedziałbyś, z której tabeli pochodzi. Nawet pisząc złączenie, dane zwrócone do oprogramowania miałyby pole z zerowymi danymi, które nadal wymagałoby również przetestowania tego.
Nicholas Aguirre,
13

Oprócz wszystkich problemów z mylącymi programistami NULL, NULL mają jeszcze jedną bardzo poważną wadę: wydajność

Kolumny NULL są katastrofą z punktu widzenia wydajności. Rozważmy arytmetykę liczb całkowitych jako przykład. W zdrowym świecie bez wartości NULL można łatwo wektoryzować arytmetykę liczb całkowitych w kodzie silnika bazy danych za pomocą instrukcji SIMD, aby wykonać prawie dowolne obliczenia przy prędkościach większych niż 1 wiersz na cykl procesora. Jednak w chwili wprowadzenia wartości NULL musisz zająć się wszystkimi specjalnymi przypadkami, które tworzy NULL. Nowoczesne zestawy instrukcji procesora (czytaj także: x86 / x64 / ARM i logika GPU) po prostu nie są przygotowane do tego, aby to zrobić skutecznie.

Rozważ podział jako przykład. Na bardzo wysokim poziomie jest to logika, której potrzebujesz z liczbą całkowitą inną niż null:

if (b == 0)
  do something when dividing by error
else
  return a / b

Z NULL staje się to nieco trudniejsze. Razem z btobą potrzebujesz wskaźnika, jeśli bjest zerowy i podobnie dla a. Czek staje się teraz:

if (b_null_bit == NULL)
   return NULL
else if (b == 0) 
   do something when dividing by error
else if (a_null_bit == NULL)
   return NULL
else 
   return a / b

Arytmetyka NULL działa znacznie wolniej na nowoczesnym procesorze niż arytmetyka nie zerowa (około 2-3 razy).

Gorzej, gdy wprowadzisz SIMD. Dzięki SIMD nowoczesny procesor Intel może wykonywać 4 x 32-bitowe podziały liczb całkowitych w jednej instrukcji, jak to:

x_vector = a_vector / b_vector
if (fetestexception(FE_DIVBYZERO))
   do something when dividing by zero
return x_vector;

Istnieją również sposoby radzenia sobie z wartością NULL w SIMD, ale wymaga to użycia większej liczby wektorów i rejestrów procesora oraz sprytnego maskowania bitów. Nawet przy dobrych sztuczkach, spadek wydajności arytmetyki liczb całkowitych NULL wkracza do 5-10x wolniejszego zakresu, nawet dla stosunkowo prostych wyrażeń.

Coś podobnego do powyższego dotyczy agregatów i do pewnego stopnia również złączeń.

Innymi słowy: Istnienie NULL w SQL jest niedopasowaniem impedancji między teorią baz danych a rzeczywistym projektowaniem współczesnych komputerów. Jest całkiem dobry powód, dla którego NULL myli deweloperów - ponieważ liczba całkowita nie może być NULL w większości rozsądnych języków programowania - po prostu nie tak działają komputery.

Thomas Kejser
źródło
10

Ciekawe pytania

Mogę tylko myśleć o tym, że jako twórca aplikacji nie musiałbyś testować NULL i możliwej nieistniejącej wartości danych (na przykład pusty ciąg znaków dla łańcuchów).

To jest bardziej skomplikowane. Null ma wiele wyraźnych znaczeń, a jednym naprawdę ważnym powodem, aby nie dopuszczać wartości null w wielu kolumnach jest to, że gdy kolumna ma wartość null, oznacza to jedną i tylko jedną rzecz (mianowicie to, że nie pojawiła się w złączeniu zewnętrznym). Dodatkowo pozwala ustalić minimalne standardy wprowadzania danych, co jest naprawdę pomocne.

Ale co robisz w przypadku dat, godziny i godziny (SQL Server 2008)? Będziesz musiał skorzystać z jakiejś historycznej lub oddolnej daty.

To od razu ilustruje problem z zerami, mianowicie, że wartość przechowywana w tabeli może oznaczać „ta wartość nie ma zastosowania” lub „nie wiemy”. W przypadku ciągów pusty ciąg może służyć jako „nie dotyczy”, ale w przypadku dat i godzin nie ma takiej konwencji, ponieważ nie ma prawidłowej wartości, co konwencjonalnie to oznacza. Zazwyczaj utkniesz przy użyciu wartości NULL.

Istnieją sposoby na obejście tego (poprzez dodanie większej liczby relacji i łączenie), ale stwarzają one dokładnie takie same problemy z klarownością semantyczną, jakie mają wartości NULL w bazie danych. W przypadku tych baz danych nie martwiłbym się tym. Po prostu tak naprawdę nic na to nie poradzisz.

EDYCJA: Jednym z obszarów, w których wartości NULL niezbędne, są klucze obce. Tutaj zazwyczaj mają tylko jedno znaczenie, identyczne z null w zewnętrznym znaczeniu łączenia. Jest to oczywiście wyjątek od problemu.

Chris Travers
źródło
10

Artykuł Wikipedii na temat SQL Null zawiera kilka interesujących uwag na temat wartości NULL, a jako odpowiedź niezależna od bazy danych, o ile masz świadomość potencjalnego wpływu posiadania wartości NULL dla określonego RDBMS, są one dopuszczalne w twoim projekcie. Gdyby tak nie było, nie można określić kolumn jako zerowalnych.

Pamiętaj tylko o tym, w jaki sposób RDBMS obsługuje je w operacjach SELECT, takich jak matematyka, a także w indeksach.

Derek Downey
źródło
-12

Wow, prawidłowa odpowiedź „Nie zezwalaj na wartości NULL, kiedy nie musisz, ponieważ obniżają one wydajność” to jakoś ostatnia ocena. Będę głosować i opracowywać. Gdy RDBMS zezwala na wartości NULL dla niesparowanej kolumny, kolumna ta jest dodawana do mapy bitowej, która śledzi, czy wartość jest równa NULL dla każdego wiersza. Zatem dodając zdolność NULL do kolumny w tabeli, w której wszystkie kolumny nie zezwalają na wartości NULL, zwiększasz przestrzeń dyskową wymaganą do zapisania tabeli. Ponadto wymaga się od RDBMS odczytu i zapisu mapy bitowej, co obniża wydajność wszystkich operacji.

Ponadto w wielu przypadkach zezwolenie na wartości NULL spowoduje uszkodzenie 3NF. Chociaż nie jestem zwolennikiem 3NF, jak wielu moich kolegów, rozważ następujący scenariusz:

W tabeli Person znajduje się kolumna o nazwie DateOfDeath, która ma wartość null. Jeśli dana osoba umarła, zostanie ona wypełniona datą śmierci, w przeciwnym razie pozostanie NULL. Istnieje również niezerowa kolumna bitowa o nazwie IsAlive. Ta kolumna ma wartość 1, jeśli osoba żyje, i 0, jeśli osoba nie żyje. Zdecydowana większość procedur przechowywanych korzysta z kolumny IsAlive, obchodzi ich tylko to, czy dana osoba żyje, a nie ich DateOfDeath.

Jednak kolumna IsAlive łamie normalizację bazy danych, ponieważ można ją całkowicie uzyskać z DateOfDeath. Ale ponieważ IsAlive jest wbudowane w większość SP, prostym rozwiązaniem jest sprawienie, aby DateOfDeath nie miało wartości zerowej, i przypisanie wartości domyślnej do kolumny w przypadku, gdy osoba nadal żyje. Nieliczne SP, które używają DateOfDeath, mogą następnie zostać przepisane, aby sprawdzić kolumnę IsAlive i honorować DateOfDeath tylko wtedy, gdy dana osoba nie żyje. Ponownie, ponieważ większość SP interesuje się tylko IsAlive (nieco), a nie DateOfDeath (data) przy użyciu tego wzorca znacznie przyspiesza dostęp.

Przydatnym skryptem T-SQL do znajdowania zerowalnych kolumn bez wartości NULL we wszystkich schematach jest:

select 'IF NOT EXISTS (SELECT 1 FROM ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name) + ' WHERE ' + QUOTENAME(c.name) + ' IS NULL)
    AND (SELECT COUNT(*) FROM ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name) + ') > 1 PRINT ''' + s.name + '.' + t.name + '.' + REPLACE(c.name, '''', '''''') + ''''
    from sys.columns c
    inner join sys.tables t ON c.object_id = t.object_id
    inner join sys.schemas s ON s.schema_id = t.schema_id
    where c.is_nullable = 1 AND c.is_computed = 0
    order by s.name, t.name, c.name;

Jeśli uruchomisz to na kopii produkcyjnej bazy danych, możesz znaleźć kolumny oznaczone przez programistów jako zezwalające na wartości NULL, które w praktyce nie mają wartości NULL. Zdecydowana większość z nich może być oznaczona jako NOT NULL, co zwiększa wydajność i zmniejsza przestrzeń dyskową.

Może nie być możliwe wyeliminowanie wszystkich wartości NULL we wszystkich tabelach i nadal mieć czysty wygląd, ale istnieje znaczna zaleta w eliminowaniu jak największej liczby wartości NULL. Optymalizator działa znacznie szybciej z tymi informacjami, a jeśli możesz wyeliminować wszystkie wartości NULL w tabeli, możesz odzyskać znaczną ilość miejsca do przechowywania.

Wiem, że wydajność nie jest czymś, o czym DBA myślą tak dużo, ale możesz wrzucić rozwiązanie tylko ograniczoną ilość pamięci i mocy procesora, w pewnym momencie będziesz musiał zacząć myśleć o logicznym i fizycznym projekcie .

Zauważ też, że dotyczy to tylko prawdziwych RDBMS i opieram techniczną część moich odpowiedzi na SQL Server. Wymieniony T-SQL do wyszukiwania zerowalnych kolumn bez wartości null pochodzi również z SQL Server.

Matthew Sontum
źródło
1
Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
Paul White