Typ danych do przechowywania tablicy flag (mapa bitowa / tablica bitów)

15

Muszę przechowywać tablicę bitów dla każdego rekordu tabeli, obsługując następujące operacje:

  • Testowanie, czy bit jest ustawiony, i ustawianie bitu (za pomocą SQL)

  • Zapytanie i ustawienie wartości za pomocą ADO 2.8 (nie ADO.NET)

  • Indeksowanie (w celu skorzystania z funkcji „indeksu obejmującego”)

Maksymalna liczba bitów przechowywanych w tej tablicy jest stała, ale może przekraczać 32 . Oznacza to, że prosta kolumna int nie zawsze działa.

Z tego, co widziałem do tej pory, moje opcje to:

  1. Użyj kilku kolumn int
  2. Użyj biginta (działa, dopóki liczba bitów wynosi <= 64)
  3. Użyj binarnego
  4. ?

Pierwsza opcja działałaby, ale wymaga sporo refaktoryzacji w kodzie, który uzyskuje dostęp do danych. Druga opcja to tylko tymczasowa ulga, a do tej pory nie jestem pewien, czy ADO działa tak dobrze z bigintem . Nie mam doświadczenia z binarnymi i nie znam innych opcji.

Jaki typ danych wybierzesz, biorąc pod uwagę wymagania?

krlmlr
źródło

Odpowiedzi:

12

Nie mogę bronić wystarczająco mocno, aby nie używać do tego jednego pola.

Obecnie zajmuję się utrzymywaniem bardzo dużego zestawu danych z bigintpolem maski bitowej i to trochę koszmar wydajności.

Jeśli zaznaczysz pojedynczy bit, wszystko będzie dobrze. Jeśli zaznaczysz więcej niż jeden bit, wydajność pogarsza się bardzo szybko.

Ze względu na naturę liczb całkowitych maski bitowej dystrybucja danych będzie bardzo niezrównoważona i otrzymasz plany nieoptymalne.

Wielokrotne sprawdzenie bitów powoduje skanowanie zakresu lub indeksu z funkcją działającą na każdym wierszu. To bałagan.

Moje obejście było proste - stworzyłem tabelę do przechowywania PK dla każdego z warunków, które należy sprawdzić. Jest to początkowo sprzeczne z intuicją, ale potrzeba miejsca jest niewielka (przechowujesz tylko PK), a wyszukiwania są błyskawiczne, szczególnie jeśli używasz UNIQUE CLUSTERED INDEX.

Możesz dodać dowolną liczbę warunków bez wpływu na główny stół, a aktualizacje również nie wpływają na główny stół.

Indeksowanie jest proste, ponieważ indeksujesz wszystkie tabele wyszukiwania indywidualnie, a ponieważ klucz klastrowany jest taki sam w głównej tabeli, a wyszukiwania merge joinsą bardzo wydajne.

JNK
źródło
1
Czy mógłbyś rozwinąć nieco więcej swojego obejścia? Znalazłem to, ponieważ próbuję rozwiązać ten sam podstawowy problem, ale nie jestem pewien, jak najlepiej to zrobić.
Joshua Frank
4

Jeśli wszystko, co musisz zapisać, to umiarkowana liczba wartości prawda / fałsz, możesz użyć bittypu danych.

Wewnętrznie SQL Server przechowuje bitkolumny spakowane w bajtowe „porcje”. Tak więc dla maksymalnie 8 bitkolumn w tabeli SQL przechowuje to jako spakowany 1 bajt; 9-16 bitkolumn w 2 bajtach i tak dalej.

Nie brzmi to tak, jakbyś zbliżał się do limitu kolumny, więc wydaje się to dość proste. Oczywiście utrzymywanie ich w dobrym stanie pozwala na nazwanie kolumn w celu zapewnienia czytelności i uzyskanie wszystkich możliwości indeksowania, jakie normalnie byś zrobił (jeśli flagi są wysoce selektywne, przefiltrowane indeksy mogą być przydatne, jeśli możesz kierować reklamy na 2008+).

Samodzielne pakowanie bitów znacznie bardziej skomplikuje indeksowanie (prawdopodobnie bitkolumny obliczane i indeksowane do reprezentowania każdej pozycji maski ... ale wtedy masz gorsze wyniki niż używanie bitbezpośrednio).

Jon Seigel
źródło