Utworzyłem następującą tabelę:
CREATE TABLE dbo.TestStructure
(
id INT NOT NULL,
filler1 CHAR(36) NOT NULL,
filler2 CHAR(216) NOT NULL
);
a następnie utworzył indeks klastrowany:
CREATE CLUSTERED INDEX idx_cl_id
ON dbo.TestStructure(id);
Następnie zapełniłem go 30 wierszami, każdy rozmiar to 256 bajtów (na podstawie deklaracji tabeli):
DECLARE @i AS int = 0;
WHILE @i < 30
BEGIN
SET @i = @i + 1;
INSERT INTO dbo.TestStructure (id, filler1, filler2)
VALUES (@i, 'a', 'b');
END;
Teraz na podstawie informacji, które przeczytałem w książce „Zestaw szkoleniowy (egzamin 70-461): Sprawdzanie Microsoft SQL Server 2012 (Itzik Ben-Gan)”:
SQL Server wewnętrznie organizuje dane w pliku danych na stronach. Strona jest jednostką o wielkości 8 KB i należy do jednego obiektu; na przykład do tabeli lub indeksu. Strona to najmniejsza jednostka do czytania i pisania. Strony są dalej uporządkowane w zakresie. Zakres składa się z ośmiu kolejnych stron. Strony z zakresu mogą należeć do jednego obiektu lub wielu obiektów. Jeśli strony należą do wielu obiektów, wówczas zasięg nazywany jest zasięgiem mieszanym; jeśli strony należą do jednego obiektu, wówczas zasięg nazywany jest zasięgiem jednolitym. SQL Server przechowuje pierwsze osiem stron obiektu w różnych zakresach. Gdy obiekt przekracza osiem stron, SQL Server przydziela dodatkowe jednolite zakresy dla tego obiektu. Dzięki tej organizacji małe obiekty marnują mniej miejsca, a duże obiekty są mniej rozdrobnione.
Więc tutaj mam pierwszą stronę o rozmiarze 8KB o mieszanym rozmiarze, wypełnioną 7680 bajtami (wstawiłem 30 razy 256-bajtowy wiersz wielkości, więc 30 * 256 = 7680), aby sprawdzić rozmiar, mam uruchomiony sprawdzanie rozmiaru proc - zwraca następujący wynik
index_type_desc: CLUSTERED INDEX
index_depth: 1
index_level: 0
page_count: 1
record_count: 30
avg_page_space_used_in_percent: 98.1961947121324
name : TestStructure
rows : 30
reserved : 16 KB
data : 8 KB
index_size : 8 KB
unused : 0 KB
Tak więc 16 KB jest zarezerwowanych dla tabeli, pierwsza strona 8 KB dotyczy strony root IAM, druga strona do przechowywania danych liści, która ma 8 KB z zajętością ~ 7,5 KB, teraz kiedy wstawię nowy wiersz z 256 bajtami:
INSERT INTO dbo.TestStructure (id, filler1, filler2)
VALUES (1, 'a', 'b');
nie jest przechowywany na tej samej stronie, chociaż ma przestrzeń 256 bajtów (7680 b + 256 = 7936, która wciąż jest mniejsza niż 8 KB), tworzona jest nowa strona danych, ale ten nowy wiersz może być dopasowany do tej samej starej strony , dlaczego SQL Server tworzy nową stronę, skoro może zaoszczędzić miejsce i czas wyszukiwania, kupując wstawianie jej na istniejącą stronę?
Uwaga: to samo dzieje się w indeksie sterty.