SERWER SQL Przechowywanie TinyInt

12

W SQL Server dlaczego maleintka jest przechowywana z 9B w wierszu. Z jakiegoś powodu wydaje się, że na końcu maski bitmapowej NULL jest dodatkowy jeden bajt.

    USE tempdb;
    UDAĆ SIĘ

    UTWÓRZ TABELĘ tbl
    (
        i TINYINT NOT NULL
    );
    UDAĆ SIĘ

    INSERT INTO tbl (i)
        WARTOŚCI (1);
    UDAĆ SIĘ

    DBCC IND („tempdb”, „tbl”, - 1);
    UDAĆ SIĘ

    DBCC TRACEON (3604); - Zrzut strony przejdzie do konsoli
    UDAĆ SIĘ

    STRONA DBCC („tempdb”, 1,168,3);
    UDAĆ SIĘ

Wyniki (odwróciłem bajty, ponieważ strona DBCC pokazuje najpierw najmniej znaczący bajt):

Record Size = 9B
10000500 01010000 00
TagA = 0x10 = 1B
TagB = 0x00 = 1B
Null Bitmap Offset = 0x0005 = 2B
Our integer column = 0x01 = 1B
Column Count = 0x0001 = 2B
NULL Bitmap = 0x0000 = 2B (what!?)
ooutwire
źródło
1
Czy to tylko edukacyjne? Jestem za przycinaniem przestrzeni w razie potrzeby, ale prawdopodobnie nie jest to 1 bajt, o który będę się martwić ...
Aaron Bertrand
To jest edukacyjne. Moja następna rozmowa SQLSaturday dotyczy kompresji; dlatego stworzyłem przykłady dla każdego typu danych, aby pomóc ludziom zrozumieć implikacje ich wyboru typu danych i pokazać wpływ kompresji na wszystkie typy danych.
ooutwire,
Zakładałem, że tinyint będzie przechowywany jako 1B (to znaczy) z 7B narzutu. Zastanawiam się, jaki jest dodatkowy bajt na końcu rekordu ???
ooutwire,
Widzę różne wyniki (choć nie jestem pewien, czy są bardziej zgodne z oczekiwaniami), gdy kolumna TINYINT nie jest jedyną kolumną w tabeli. Wygląda na dość rzadki przypadek użycia.
Aaron Bertrand
Z pewnością nie jest to powszechny problem w przypadku użycia. Właśnie próbowałem pokazać każdy typ danych osobno, aby zmniejszyć koszty ogólne związane z przechowywaniem i pozwolić początkującym zobaczyć, jak kolumna wygląda na stronie. Wydaje mi się dziwne, że dodatkowy bajt ... doprowadza mnie do szału, aby go zobaczyć i bez powodu.
ooutwire,

Odpowiedzi:

12

Jeśli obliczysz rekord za pomocą prostego dodania rozmiaru, rzeczywiście otrzymasz 8: 4 + 1 + 2 + 1 (nagłówek + ustalony rozmiar + zerowa liczba bitmap + sama pusta bitmapa). Ale rekord stosu nie może być mniejszy niż rozmiar kodu przekierowującego , który wynosi 9 bajtów, ponieważ rekord musi gwarantować , że można go zastąpić kodem przekierowującym. Stąd rekord będzie faktycznie o 9 bajtów. A smallintbędzie mieć 9 bajtów zarówno za pomocą obliczeń, jak i rozmiaru minimalnego. Coś większego jest już większe niż kod pośredniczący przesyłania, więc Twój rozmiar obliczeniowy jest zgodny z rozmiarem rekordu.

Remus Rusanu
źródło
9 bajtów dotyczy również tej definicji, CREATE TABLE tbl (i TINYINT NOT NULL PRIMARY KEY)więc czy jest to tylko ogólna reguła dla wszystkich wierszy, niezależnie od tego, czy są one częścią stosu?
Martin Smith,
1
B-drzewo może zostać przekształcone w stercie ( alter table ... drop constraint), a operacja nie jest pełną przebudową (górne strony b-drzewa zostają wyrzucone, strony liści pozostaną rozłączone, a wynikiem jest sterta), więc logika rezerwacji nadal obowiązuje .
Remus Rusanu,
Myślę, że to dowodzi, co powiedział Remus ... Improv.dk/archive/2011/06/07/…
ooutwire
6

Miło mieć ucho autora. :-) Kalen podejrzewa, że ​​jest to tylko egzekwowanie pewnej minimalnej długości wiersza, gdzie wszystko <9 jest dopełniane do 9. Oczywiście jest tylko kilka przypadków, w których jest to możliwe. Ten fantomowy bajt znajdziesz dla TINYINT i BIT, a także VARCHAR (1) / CHAR (1). Nie wzrośnie powyżej 9, jeśli przejdziesz do SMALLINT lub CHAR (2), ale wzrośnie, jeśli przejdziesz do, powiedzmy, CHAR (3).

Zasadniczo możesz więc wskazać wydajność, którą możesz zyskać, mądrze wybierając typy danych, ale zwróć uwagę, że istnieją pewne przypadki skrajne, w których reguły nie obowiązują z powodu innych czynników w warstwie pamięci.

EDYTUJ Mam nadzieję, że będę miał dla ciebie bardziej konkretne informacje. Chciałem tylko poinformować, że tak właśnie myśli obecnie autor książki o Internals. Nie jest w 100% pewna.

Aaron Bertrand
źródło
Dziękujemy Aaronowi za skontaktowanie się z Kalenem. Wczoraj przeglądałem tę książkę i wyciągałem włosy. To trochę tak, jak dodatkowe bajty metadanych dla sql_variant, z wyjątkiem tego, że nie mam sposobu na wyjaśnienie bajtu fantomowego oprócz machania ręką i krzyczenia: „Tak to jest kolego!”
ooutwire
1
Cóż, możesz połączyć ten komentarz z „jest to skrajny przypadek skrajny, ponieważ niewiele tabel jest zaprojektowanych tak, aby próbować przechowywać pojedynczy malutki lub char (1) w każdym rzędzie”.
Aaron Bertrand