Tinyint vs Bit?


81

Nie chcę tu wywoływać wojny religijnej, ale wydaje się, że istnieją dwie szkoły myślenia o tym, jak przedstawiać wartości logiczne w bazie danych. Niektórzy twierdzą, że bitjest to odpowiedni typ danych, podczas gdy inni twierdzą, że tinyintjest lepszy.

Jedyne różnice, o których wiem, to:

  • bit: rozmiar pamięci to 1 bit, możliwe wartości to 0 lub 1
  • tinyint: rozmiar pamięci to 1 bajt, możliwe wartości to 0-255

Który typ danych jest lepszy, gdy chcesz przedstawić wartości logiczne? Czy tinyintwarte są dodatkowego narzutu „na wszelki wypadek”, którego potrzebujesz do wartości> 1?


1
„Na wszelki wypadek” wydaje się być dość płynnym projektem bazy danych. Dlaczego nie przechowywać wszystkiego jako NVARCHAR (MAX) i pokryć wszystkie swoje bazy?
Stuart Ainsworth

TinyInt to moje preferencje. Następnie, wykonując zagregowane liczenia względem pola, nie musisz go rzucać. Ponadto niektóre języki frontonu interpretują Bit inaczej niż inne, a użycie TinyInt sprawia, że ​​sprawdzanie poprawności jest uniwersalne dla każdego języka interfejsu użytkownika.
Gregory Hart

Właśnie spotkałem się z dziwactwem związanym z bitem w phpMyAdmin. Kiedy mówię mu, aby pole miało wartość NULL i żadna wartość domyślna nie jest ustawiona, domyślnie przyjmuje wartość <em> NULL </em> zamiast NULL. +1 dla tinyint btw
Vörös Amadea

podczas importu formularza csv plik 1 działa w przypadku tinyint (1), ale w przypadku bitu (1) należy go zamienić na b'1 '
Rajat

Odpowiedzi:


90

Kiedy dodasz bitową kolumnę do swojej tabeli, zajmie ona cały bajt w każdym rekordzie, a nie tylko pojedynczy bit. Po dodaniu drugiej kolumny bitowej zostanie ona zapisana w tym samym bajcie. Dziewiąta kolumna bitowa będzie wymagać drugiego bajtu pamięci. Tabele z kolumną 1-bitową nie będą miały żadnej korzyści z przechowywania.

Tinyint i wędzidło mogą działać zarówno z powodzeniem, jak i bez silnych preferencji.


To bardzo pomocny komentarz, a twoja reputacja jest całkiem dobra, ale czy masz jakieś referencje, które ją potwierdzają? Czy jest to szczegół implementacji, czy też wszystkie silniki obsługują to w ten sam sposób?
Jon z

3
@Jonz Zobacz tutaj MySQL.
shmosel

Z odniesienia @shmosel jasno wynika, że ​​kolumna 1 bit (1) zajmuje 1 bajt, ale nie jest tak jasne, że dwie, trzy, cztery… aż osiem bitowych (1) kolumn zajmuje ten sam bajt. Szukałem tego w Internecie bez powodzenia. Czy mógłbyś się do tego odnieść? Interesuje mnie tylko to, czy w przypadku, gdybym miał, powiedzmy, cztery kolumny boolowskie, których potrzebuję do mojej tabeli, warto użyć kolumny bit (1) zamiast tinyint (1) s, aby zaoszczędzić miejsce. Dziękuję Ci.
assensi

@assensi Słuszna uwaga. Zawsze możesz użyć jednego BIT(n)zamiast npól. Lub możesz użyć zwykłego INTi przechowywać każdą wartość logiczną jako kawałek. Ale jeśli masz zamiar z oddzielnymi polami, myślę, że TINYINTjest zwykle preferowane do BITMySQL.
shmosel

19

Bit ... chyba że należysz do klanu "prawda / fałsz / nie znaleziono pliku"

Na wypadek, gdybyś nie otrzymał referencji ...

A w przypadku Linq2SQL bit działa z prawdą / fałszem, co ułatwia programowanie. Obie mają zalety.

Należy również wziąć pod uwagę konserwację oprogramowania. Co się stanie, jeśli Ty (lub młodszy programista-stażysta) używasz 2, 3, 25, 41, 167, 200 itd.? Gdzie to jest udokumentowane? Bity same się dokumentują i są dość uniwersalne.


11
bity dopuszczają wartość null, więc nadal możesz mieć T / F / FNF.
Austin Salonen

3
A jak złe jest NULL równe FNF? :) Naprawdę godny thedailywtf!
John Rudy

@Pratik problem ma wartość NULL, co oznacza, że ​​w bazie danych nie ma wartości. Nie oznacza to, że plik nie został znaleziony. Zrób to, a zaczniesz niejawnie kodować stany w wierszach, które są trudne do udokumentowania i mylące. To trochę tak, jakbyś miał tabelę przedmiotów. Jak sprawdzić, czy przedmiot został sprzedany? Mógłbym sprawdzić, czy ma cenę sprzedaży, datę sprzedaży, nazwę kupującego itp. Lub mogę wymusić to wszystko za pomocą ograniczenia sprawdzającego i utworzyć pole bitowe dla sprzedanych przedmiotów.
CodeMonkey,

15

W razie potrzeby używam końcówek. Oprócz tego, że jest to poprawny semantycznie typ (liczba semantyki!), Wiele pól bitowych (do 8) w jednym wierszu (w każdym razie na serwerze SQL) można skonsolidować w jeden bajt pamięci. Po ósmej potrzebny jest dodatkowy bajt dla następnych 8 i tak dalej.

Bibliografia:




2

Boolean z definicji dopuszcza tylko dwie wartości. Dlaczego potrzebujesz do tego czegoś więcej niż jednego kawałka? jeśli potrzebujesz logiki z trzema (lub więcej) stanami, użyj większego typu danych, ale trzymałbym się (i robię) z polami bitowymi dla standardowej logiki boolowskiej.


2

Używam bitu, ponieważ oszczędza mi to konieczności używania ograniczenia sprawdzającego i ponieważ mój ORM automatycznie konwertuje bit na wartość logiczną dopuszczającą wartość zerową (C #), co bardzo doceniam po zakodowaniu.


2

Zero miejsca na fałsz

Cokolwiek wybierzesz, możesz ustawić NULLzamiast 0i nie zajmie to dodatkowego miejsca (ponieważ baza danych prawie zawsze ma NULLflagę dla każdego pola w każdym wierszu, po prostu tam siedzi; więcej informacji tutaj ). Jeśli również upewnisz się, że domyślną / najbardziej prawdopodobną wartością jest false, zaoszczędzisz jeszcze więcej miejsca!

Trochę miejsca na prawdę

Wartość do przedstawienia truewymaga przestrzeni zdefiniowanej przez typ pola; użycie BITpozwoli zaoszczędzić miejsce tylko wtedy, gdy tabela ma wiele takich kolumn, ponieważ wykorzystuje jeden bajt na 8 pól (w przeciwieństwie do tego, TINYINTktóry wykorzystuje jeden bajt na pole).

TINYINTma tę zaletę, że pozwala dostosować 8-wartościową maskę bitową bez martwienia się o zarządzanie kilkoma dodatkowymi kolumnami, a wyszukiwanie jest teoretycznie szybsze (pojedyncze pole liczb całkowitych w porównaniu z kilkoma polami bitowymi). Ale są pewne wady, takie jak wolniejsze porządkowanie, fantazyjne indeksowanie krzyżowe i brak nazw pól. Która dla mnie jest największą stratą; Twoja baza danych wymagałaby zewnętrznej dokumentacji, aby odnotować, które bity robią co w których maskach bitowych.

W każdym razie unikaj pokusy używania TEXTpól do przechowywania wartości logicznych lub ich zbiorów. Przeszukiwanie tekstu wymaga dużo więcej pracy dla serwera, a dowolne schematy nazewnictwa, takie jak „włącz, wyłącz, wyłącz” mogą zaszkodzić interoperacyjności.


1

Właśnie próbowałem grupować na bit (SQL Server 2k5) i działało dobrze. Lubię używać prawidłowego typu danych dla aplikacji. Jeśli jest to pole prawda / fałsz, używam bitu ...


1

Wszystkie te teoretyczne dyskusje są świetne, ale w rzeczywistości, przynajmniej jeśli używasz MySQL i naprawdę również dla SQLServer, najlepiej jest trzymać się danych niebinarnych dla swoich wartości logicznych z tego prostego powodu, że łatwiej jest z nimi pracować, gdy wyprowadzanie danych, wysyłanie zapytań i tak dalej. Jest to szczególnie ważne, jeśli próbujesz osiągnąć interoperacyjność między MySQL i SQLServer (tj. Synchronizujesz dane między nimi), ponieważ obsługa typu danych BIT jest różna w obu z nich. WIĘC w praktyce będziesz miał dużo mniej kłopotów, jeśli będziesz trzymać się numerycznego typu danych. Poleciłbym MySQL trzymać się z BOOL lub BOOLEAN, który jest przechowywany jako TINYINT (1). Nawet sposób, w jaki MySQL Workbench i MySQL Administrator wyświetlają typ danych BIT, nie jest przyjemny (to mały symbol danych binarnych).


1

Wydaje mi się, że nie widziałem tego wspomnianego powyżej, ale występuje problem braku możliwości agregowania kolumn BIT (np. MIN, MAX, a zwłaszcza SUM). Właśnie przetestowałem przy użyciu 2008 i problem nadal występuje. To jest największy powód, dla którego ostatnio używam tinyint - z drugiej strony lubię to, jak tinyint się skaluje - zawsze jest uciążliwe, gdy twoja flaga bitowa o wartości dwóch wartości nagle potrzebuje więcej możliwych wartości.


1
Możesz je zagregować, rzutując je na inny typ danych - po co jednak sumować wartość prawda / fałsz?
Martin Smith

2
Często grupujemy na jednym polu i podsumowujemy, ile innych pól jest prawdziwych dla każdej grupy według wyniku, alternatywą dla sumowania byłoby zwrócenie całego wyniku do kodu i zapętlenie go tam, co czasami skutkuje zwróceniem 1000 razy więcej danych do klienta . Ale casting to eliminuje, więc nie stanowi to problemu.
David Mårtensson

0

Wszystkie nasze tabele budujemy z polem „wektor” int. Następnie używamy tego pola jako zbioru 32 bitów, które możemy przypisać do dowolnego celu. (Potencjalnie przy użyciu grupy bitów dla zestawu stanów). Pozwala uniknąć konieczności ciągłego dodawania pól flag, jeśli zapomnimy.


2
Nazywa się to również zaciemnianiem. Lub, dla laika, „koszmar konserwacji”.
Robert C. Barth

6
Możesz po prostu uczynić wszystkie swoje tabele jedną kolumną TEKST i umieścić tam wszystko rozdzielone przecinkami. Wtedy nigdy nie musiałbyś zmieniać modelu danych.
Tom H

1
Mamy dość wyjątkowe środowisko. Mamy bardzo duże zbiory danych ORAZ czas pracy 4 9, więc zmiana tabel jest raczej zaporowa (dwukrotnie większa w przypadku replikacji). Śledzimy wszystkie bity w scentralizowanej lokalizacji, co pomaga uniknąć problemu z konserwacją.
Joe

0

@Kevin: Uważam, że można używać group byna polach bitowych (SQL Server 2005):

declare @t table (
    descr varchar(10),
    myBit1 bit, 
    myBit2 bit
)
insert into @t values ('test1', 0, 1)
insert into @t values ('test2', 1, 0)
insert into @t values ('test3', 1, 1)
insert into @t values ('test4', 0, 0)

select myBit1, count(myBit1) from @t group by myBit1
select myBit2, count(myBit1) from @t group by myBit2

Wyniki:

myBit1 
------ -----------
0      2
1      2

myBit2 
------ -----------
0      2
1      2

0

TinyInt to moje preferencje. Następnie, wykonując zagregowane liczenia względem pola, nie musisz go rzucać. Ponadto niektóre języki frontonu interpretują Bit inaczej niż inne, a użycie TinyInt sprawia, że ​​sprawdzanie poprawności jest uniwersalne dla każdego języka interfejsu użytkownika.



-2

Lubię używać char (1) z „T” lub „F”. Tak, można go nadużywać z innymi wartościami, ale przynajmniej jest łatwy do przeglądania w raportach lub innych miejscach, w których trudniej jest pracować z wartościami bitowymi lub binarnymi.


2
Możesz (i powinieneś) łatwo dodać ograniczenie do kolumny, aby zezwalać tylko na „T” i „F”. W związku z tym warstwa raportowania powinna być CAŁKOWICIE ODDZIELONA od bazy danych. Nie należy zmieniać schematu bazy danych tylko ze względu na sposób wyświetlania kolumny.
Tom H

Zgadzam się z Darrylem. Biorąc pod uwagę brak wsparcia dla typów boolowskich w ogólnych systemach RDBMS (MySQL nie jest tutaj sam) T / F (właściwie wolę T / N) jest znacznie bardziej czytelny. Chociaż w zasadzie zgadzam się z komentarzami Toma H. ​​uważam, że czytelność jest dużo ważniejsza, niż przyznaje. Deweloperzy baz danych nie patrzą na interfejs użytkownika podczas zmiany kodu innej osoby! Ponadto nie zawsze jest jasne, w którą stronę programista uważa 1 i 0. Gdybyśmy wszyscy robili to w „właściwy”, staromodny sposób, używalibyśmy go -1do przedstawiania prawdy i 0fałszu.
wóz przed koniem

W moim poprzednim komentarzu powinienem dodać, że wygląda na to, że MySQL nie obsługuje ograniczeń CHECK, co skomplikowałoby opcję T / F, ponieważ nie można zapobiec wypełnieniu kolumny jakimkolwiek innym znakiem alfabetu. Niemiły.
wóz przed koniem
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.