Zalety i wady stosowania masek bitowych w bazie danych

22

Nie tak dawno temu rozmawiałem z moim kolegą i zdecydowanie był przeciwny stosowaniu masek bitowych, ponieważ trudno jest zrozumieć wszystkie wartości przechowywane w bazie danych. Moim zdaniem korzystanie z nich nie zawsze jest złym pomysłem, na przykład w celu określenia ról bieżącego użytkownika. W przeciwnym razie musisz przechowywać go w osobnej tabeli, co spowoduje jeszcze jeden DOŁĄCZ. Czy możesz mi powiedzieć, jeśli się mylę? Jakieś inne skutki uboczne, zalety / wady stosowania masek bitowych?

Alex Ovechkin
źródło
2
Bardziej sensowne może być, aby baza danych tworzyła maski bitowe wewnętrznie i prezentowała bity jako osobne kolumny. Twoje wymagania mogą ulec zmianie.
Simon Richter
1
Jeśli nie używasz sprzężeń, nie używasz relacyjnej bazy danych w zamierzony sposób.
Pieter B

Odpowiedzi:

38

Pracuję z aplikacją, która wykorzystuje maski bitowe do przechowywania przypisań ról użytkownika. To jest ból w tyłku. Jeśli to sprawia, że ​​jestem stronniczy, winny, jak oskarżony.

Jeśli korzystasz już z relacyjnej bazy danych, jest to anty-wzorzec, który narusza większość teorii relacyjnych i wszystkie reguły normalizacji. Kiedy budujesz własny magazyn danych, może to nie być taki zły pomysł.

Jest coś takiego, że łączy się zbyt wiele tabel, ale do tego służą zbudowane relacyjne bazy danych. Wiele z nich ma dodatkowe funkcje, jeśli wydajność staje się problemem: indeksy, widoki indeksowane itp. Nawet jeśli wartości, na które patrzysz, nie zmieniają się zbyt często, co jest zaletą dla maski bitowej, narzut związany z zarządzaniem indeksowaniem jest dość łatwe w bazie danych.

Chociaż baza danych dobrze agreguje dane, mogą stać się powolne, gdy zaczniesz wprowadzać takie rzeczy, jak złożone formuły lub funkcje skalarne do zestawów danych. Możesz zrobić to bitowo w swojej aplikacji, ale jeśli wszystko, co robisz, to uzyskiwanie powiązanych danych (wyszukiwanie ról użytkownika), nie korzystasz z tego, co najlepiej robi twoje przechowywanie danych.

Moim ostatnim argumentem przeciwko temu byłaby prostota dla innych programistów. Masz użytkowników, role i zadania. Jest to zestaw relacji wiele do wielu (ponieważ istnieje więcej niż jeden związek), który jest tak powszechny, że zarządzanie nim powinno być łatwe. To tylko CRUD.

JeffO
źródło
8
Relacyjna baza danych dotyczy najgorszego miejsca dla maski bitowej. Koszty przechowywania nie są już tak duże, że kilka złączeń i dodatkowy stół powinny cię złamać. Z pewnością sprawia, że ​​wszystko jest trudniejsze do uzasadnienia. Przechowuj uprawnienia jako bity (1/0) w bazie danych we własnej tabeli i reprezentuj je w kodzie za pomocą flag oprócz. Wydaje się dość odpowiednie i wykonalne. Programiści otrzymują proste flagi, a bazy danych mają znormalizowane tabele. Wszyscy są szczęśliwi.
Mike McMahon
3
Zgadzam się, kiedyś obsługiwałem aplikację, która używała masek bitowych dla ról użytkowników i uprawnień w swojej bazie danych. To był koszmar. Używając 32-bitowej liczby int, zabrakło nam bitów, więc ktoś miał świetny pomysł, aby dodać więcej masek bitowych, a następnie z nakładaniem się, więc bit 4 w jednej kolumnie oznaczał bit 8 w drugiej kolumnie i nie udało się zsynchronizować. Tak, tak. Indeksowanie było trudne, ponieważ indeksy przechowują wartości dyskretnych kolumn, a nie poszczególne bity w nich, więc nie można wyszukiwać wierszy where some_bit_mask & 12 > 0bez skanowania wiersz po wierszu.
Brandon
Pod koniec dnia, wiele-do-wielu user_role_maplub user_priv_mapstole by wystarczyło.
Brandon
@MikeMcMahon, czy mógłbyś zanurzyć się głębiej w projektowaniu tabeli i jak powinienem zmapować go w kodzie, aby osiągnąć wynik, o którym mówisz?
Alex Ovechkin
2
@usr - Nigdy nie mów nigdy. Jasne, że możesz używać masek bitowych, ale nie użyłbym ich w aplikacji korzystającej z relacyjnej bazy danych. Prawdopodobnie zdarzają się przypadki skrajne, gdy mamy do czynienia ze starszymi danymi lub nadmierną potrzebą szybkości.
JeffO
24

Wymieniłeś już odpowiednie zalety i wady:

  • Pola bitowe oszczędzają miejsce.
  • Przechowują dane w samym rekordzie, więc nie potrzebujesz JOIN, aby je znaleźć. (Ale poszczególne pola flagi w rekordzie zrobiłyby to samo.)
  • Są one słabo czytelne, jeśli chcesz produktywnie pracować z surowym wyjściem SQL.

Podjęcie decyzji co zrobić wymaga więcej informacji:

  • Jak mało jest miejsca na dysku dla twojego przypadku użycia?
  • Czy faktycznie tak często czytasz role użytkowników, że dołączenie do nich jest wąskim gardłem?
  • Czy zamierzasz czytać dane SQL i podejmować na ich podstawie decyzje - czy też nieczytelny rekord bazy danych jest nieistotny, podobnie jak fakt, że kod maszynowy twojego systemu jest nieczytelny?

Musisz więc zebrać czynniki ryzyka, a następnie zważyć je, aby sprawdzić, czy zalety przewyższają wady.

Kilian Foth
źródło
Dziękuję za odpowiedź, całkowicie zgadzam się ze swoimi przemyśleniami, ale ogólnie jest to anty-wzór, czy nie? Czy używasz masek w swoich projektach?
Alex Ovechkin,
12
@Alex Nie ma czegoś takiego jak „najlepsza praktyka”, która mogłaby zadecydować, co robić w twoim przypadku. Jeśli brakuje ci miejsca, najlepszą praktyką jest używanie pól bitowych. Jeśli chcesz używać danych wyjściowych SQL w raportach do dyrektora generalnego, najlepszą rzeczą jest używanie mówionych nazwisk. Ale jesteś jedynym, który zna te okoliczności, dlatego społeczność nie może dać ci recepty, która jest zawsze ważna.
Kilian Foth,
Traktując argument przestrzeni jako „gimme”. Pytanie, czy użyć maski bitowej, zależy od tego, czy przynosi ona jakąkolwiek korzyść ponad to.
Robbie Dee,
Czy też KAŻDY potrzebuje przetwarzania informacji w bazie danych, czy zawsze jest wczytywany do aplikacji przed użyciem?
Ian
1
„Czy zamierzasz czytać dane wyjściowe SQL i podejmować na ich podstawie decyzje - czy też nieczytelny rekord bazy danych jest nieistotny, podobnie jak fakt, że kod maszynowy twojego systemu jest nieczytelny?” Chyba nie mogę mówić za wszystkich programistów, ale kiedy się rozwijam, bardzo często zaczynam wybierać dane z bazy danych, aby coś zrozumieć lub sprawdzić. Dlatego twierdzę, że zwykle odpowiedź na to brzmi: „Tak, ktoś to zrobi”.
jpmc26
18

Jeśli jesteś naprawdę, naprawdę , naprawdę przywiązany do miejsca na dysku, to może rozważyć bitmap dla uprawnień użytkownika. Jeśli martwisz się wydajnością, zapomnij o nich całkowicie, ponieważ ich rozdzielanie będzie w rzeczywistości wolniejsze. Nie można w sposób znaczący indeksować pola bitmapowego, co powoduje skanowanie tabel bazy danych, które [prawie] zawsze są zabójcami wydajności.

O ile nie jesteś Amazonem ani Netflixem, ilość danych związanych z uprawnieniami użytkownika będzie znikoma w porównaniu do wszystkiego, co przechowujesz.

Każdy poważny DBMS może poradzić sobie z tym „dodatkowym złączeniem” nawet bez mrugnięcia okiem.

Phill W.
źródło
7
+1: Dobre relacyjne bazy danych są tworzone przez ludzi, którzy są naprawdę, naprawdę bardzo dobrzy w tym, co robią. Każdy, kto jest na poziomie wymagającym zmniejszenia ostatniej wydajności, jaką można uzyskać za pomocą pól bitowych, nie musi zadawać pytania. Modeluj dane, a następnie znajdź części, które nie działają.
Blrfl,
Dołączenie sprawi, że kod aplikacji będzie bardziej złożony, więc wiele sprowadza się do GDZIE są przetwarzane role.
Ian
4
@ Ian posiadanie sprzężenia nie wydaje się bardziej skomplikowane niż konieczność rozszyfrowania uprawnień do maskowania bitów.
Brad
@Brad, Pomyśl o wyliczeniu, które jest zbiorem flagi w języku C #, a jego wartość jest przechowywana „tak, jak jest” w bazie danych, zimno w języku C # nie może być prostsze. Jeśli używane jest sprzężenie, kod C # musi radzić sobie z relacją „1 do wielu”.
Ian
Powinienem również dodać, że jeśli masz wiele kolumn boolowskich w tabeli, większość baz danych wymyśli, jak je zmiażdżyć na tak małej przestrzeni, jak to możliwe, i zajmie się dla ciebie kręceniem bitów.
Blrfl
8

Kiedy magazynowanie było drogie, dobrodziejstwem mask bitowych było to, że oszczędzali miejsce. W czasach dużych zbiorów danych nie był to kiedyś problem.

Biorąc przykład, który przytaczasz - posiadanie ról zapisanych jako maska ​​bitowa byłoby czymś w rodzaju zapachu kodu z punktu widzenia projektu bazy danych, ponieważ naruszałoby to pierwszą normalną formę . W tym sensie są anty-wzorem.

Biorąc to wszystko pod uwagę, nie musi to być jedno lub drugie. Możesz przechowywać dane jako maskę bitową, a następnie mieć widok, który może błyskawicznie pobierać role użytkownika. Będziesz wtedy miał również możliwość szybkiego sprawdzenia, którzy użytkownicy mieli te same role.

Robbie Dee
źródło
2

Jedyną zaletą korzystania z maski bitowej jest to, że znaczenie pól bitowych nie jest statyczne. Tabele relacyjne działają dobrze tylko wtedy, gdy wiesz z góry, co każde pole jest w rekordzie: w końcu musisz zidentyfikować pola w instrukcji CREATE TABLEDDL.

Jeśli znaczenie każdego pola bitowego jest konfigurowalne w czasie wykonywania lub w inny sposób nie jest znane z wyprzedzeniem, warto zapisać wartości logiczne jako pole bitowe. Nawet wtedy, możliwe jest zdefiniowanie tabeli z dowolnych pól: field_1, field_2, itd. To daje czystsze relacyjnych, choć nadal nie jest idealny. To, czy jest to preferencyjne dla pola bitowego, jest w dużej mierze kwestią opinii, ponieważ żadne z tych rozwiązań nie jest idealne.

Jeśli wiesz, co bity reprezentują podczas programowania, utwórz pola dla każdego bitu i nadaj im sensowne nazwy .

Uważaj tylko na efekt wewnętrznej platformy . Jeśli skończysz definiować dowolne, ale dobrze wpisane pola, to jedno, ale jeśli pójdziesz o wiele dalej, odkryjesz relacyjną bazę danych ... wewnątrz relacyjnej bazy danych.


źródło
2

Jestem ambiwalentny co do masek bitowych. Uważam, że większość ich krytyków nie rozumie wartości binarnych i szesnastkowych. Dla jasności używaj dobrych mnemoników.

Zaletą niewymienioną powyżej jest możliwość dodawania nowego znaczenia do masek bitowych bez potencjalnie czasochłonnego dodawania nowej kolumny. Nasi projektanci db (którzy mnie poprzedzili) mają je w tabeli, która codziennie otrzymuje 5 milionów nowych rekordów. Dodanie nowej kolumny reprezentującej nowe zachowanie zajęłoby dużo czasu, podczas gdy zdefiniowanie nowego bitu (zużyliśmy 33 z 64) nie wymaga przebudowy tabeli.

Nie, maski bitowe nie mogą być indeksowane, ale budowanie 33 indeksów byłoby śmieszne i spowalniałoby wstawianie do indeksowania. Wyszukiwania w tabelach wykorzystują indeksy dat i rekordów „właścicieli”, dlatego indeksy tej maski bitowej, jeśli to możliwe, nigdy nie byłyby używane.

GB
źródło
To ciekawa sprawa. Przypuszczam, że można to osiągnąć w koszerny i wyraźny sposób, definiując „zapasowe” kolumny na stole, a następnie wprowadzając je w razie potrzeby. Następnie możesz przynajmniej zindeksować te kolumny selektywnie, jeśli chcesz.
Steve
1

Jeśli celem jest jedynie oszczędność miejsca na dysku, myślę, że to zły pomysł:

  • spójrz na dzisiejszy koszt GB,
  • porównajmy to z kosztem czasu tych, którzy piszą raporty i zapytania i muszą dowiedzieć się, co jest w terenie, i jak rozwiązać konkretny bit, porównanie kosztów / korzyści może skończyć się źle.
  • jeśli pracujesz z bazą danych SQL, dodatkowe operacje dostępu do bitów wymagane w wielu zapytaniach mogą również wymagać więcej czasu obliczeniowego niż to konieczne

Istnieją jednak przypadki, w których użycie pól bitowych może być uzasadnione:

  • jeśli twoje bity reprezentują złożony zestaw flag, które zawsze traktujesz razem jako całość,
  • tym bardziej, jeśli musisz zastosować algorytmy dopasowania wzorców do tych zestawów,
  • a zwłaszcza, jeśli dane te nie należą do najczęściej stosowanych kryteriów wyboru.
Christophe
źródło