it-swarm.dev

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

Pamiętam, że czytałem ten jeden artykuł o projektowaniu bazy danych i pamiętam, ż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?

127
Thomas Stringer

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, pytając mnie o moje sekrety tak długiego życia itp.

Jeśli można wprowadzić wiersz, w którym możliwe jest, że nie wiesz wartość kolumny, myślę, że NULL ma o wiele więcej sensu niż wybranie jakiejkolwiek arbitralnej wartości tokena, która reprezentuje fakt, że jest ona nieznana - wartość, którą inni będą musieli już znać, poddać inżynierii wstecznej lub poprosić o wyjaśnienie, 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 byłyby 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 może być sprawą życia lub śmierci wiedzieć , dlaczego wartość jest nieznana. Czy częstość akcji serca jest NULL, ponieważ nie było pulsu 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 uczyć się lub dyktować, kiedy i gdzie powinny być używane, a kiedy i gdzie nie powinny.

232
Aaron Bertrand

Ustalone powody to:

  • NULL nie jest wartością, a zatem nie ma wewnętrznego typu danych. Wartości null wymagają specjalnej obsługi w dowolnym miejscu , gdy kod, który w innym przypadku opiera się na rzeczywistych typach, może również otrzymać niepisaną wartość 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, a także 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 niezgodne znaczenia.

  • One nie są konieczne do relacyjnych baz danych , jak argumentowano w „Jak obsługiwać brakujące informacje bez wartości zerowych” . Dalsza normalizacja jest oczywistym pierwszym krokiem do wypróbowania tabeli NULL.

To nie znaczy, że NULL nigdy nie powinien być dozwolony. To robi argumentuje, że istnieje wiele dobrych powodów, aby nie dopuszczać NULL tam, gdzie jest to możliwe.

Co ważne, argumentuje za bardzo trudnymi próbami - dzięki lepszemu projektowaniu schematów i lepszym silnikom baz danych, a nawet lepszym językom baz danych - do make możliwe jest częstsze unikanie NULL.

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

61
bignose

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 źle rozumiane, w wyniku czego jest niewłaściwie stosowane.

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.

32

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 kilka pytań z tego samego powodu.

  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 dużo czasu spędzam przeglądając mnóstwo odpowiedzi, komentarzy, artykułów i porad w całym Internecie. 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 zakończenia. 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 on aktywny, czy zwalniany, w pewnym momencie doda datę do tego pola. To jest moim zdaniem jedyny powód, dla którego pole Nullable jest.

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 radzenia 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.

Unknown Nullable and One-to-One relationship

Wiem, że jestem trochę spóźniony na imprezę, odkąd to pytanie zostało zadane lata temu, ale mam nadzieję, że pomoże to rzucić nieco światła na tę kwestię i jak najlepiej sobie z tym poradzić.

14

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ż 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. Wraz z b będziesz potrzebował wskaźnika, jeśli b ma wartość null 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 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 poniżej:

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 obszarze 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 dla nawet stosunkowo prostych wyrażeń.

Coś podobnego do powyższego dotyczy agregatów, a do pewnego stopnia także złączeń.

Innymi słowy: Istnienie NULL w SQL jest niedopasowaniem impedancji między teorią baz danych a rzeczywistym projektowaniem współczesnych komputerów. Istnieje całkiem niezły powód, dla którego NULL dezorientuje programistó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.

13
Thomas Kejser

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, jak RDBMS obsługuje je w operacjach SELECT, takich jak matematyka, a także w indeksach.

10
Derek Downey

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 jest null, oznacza to jedną i tylko jedną rzecz (mianowicie, ż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 łączenia), 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: Jeden obszar, w którym NULL are niezbędny jest w kluczach obcych. Tutaj zazwyczaj mają tylko jedno znaczenie, identyczne z null w zewnętrznym znaczeniu łączenia. Jest to oczywiście wyjątek od problemu.

10
Chris Travers