- Ponieważ
avg_row_length
todata_length / rows
.
data_length
to w zasadzie całkowity rozmiar tabeli na dysku . Tabela InnoDB to coś więcej niż tylko lista wierszy. Więc jest to dodatkowe obciążenie.
- Ponieważ wiersz InnoDB to więcej niż dane.
Podobnie jak powyżej, każdy rząd ma pewne narzuty. Więc to zwiększy rozmiar rzędu. Tabela InnoDB to nie tylko spis danych stłoczonych razem. Do wydajnej pracy potrzebuje trochę dodatkowej pustej przestrzeni.
- Ponieważ rzeczy są przechowywane na dyskach w blokach, a te bloki nie zawsze są pełne.
Dyski przechowują rzeczy zwykle w 4K, 8K lub 16K blokach . Czasami rzeczy nie pasują idealnie do tych bloków, więc możesz uzyskać niektóre puste przestrzeń .
Jak zobaczymy poniżej, MySQL przydzieli tabelę w blokach. I przydzieli znacznie więcej, niż to konieczne, aby uniknąć konieczności powiększania tabeli (co może być powolne i prowadzić do fragmentacja dysku co sprawia, że wszystko działa jeszcze wolniej).
Aby to zilustrować, zacznijmy od pustej tabeli.
mysql> create table foo ( id smallint(5) unsigned NOT NULL );
mysql> select data_length, table_rows, avg_row_length from information_schema.tables where table_name = 'foo';
+-------------+------------+----------------+
| data_length | table_rows | avg_row_length |
+-------------+------------+----------------+
| 16384 | 0 | 0 |
+-------------+------------+----------------+
Wykorzystuje 16K lub cztery bloki 4K do przechowywania niczego. Pusta tabela nie potrzebuje tej przestrzeni, ale MySQL przydzielił ją przy założeniu, że umieścisz w niej mnóstwo danych. Pozwala to uniknąć kosztownej ponownej alokacji każdej wkładki.
Teraz dodajmy wiersz.
mysql> insert into foo (id) VALUES (1);
mysql> select data_length, table_rows, avg_row_length from information_schema.tables where table_name = 'foo';
+-------------+------------+----------------+
| data_length | table_rows | avg_row_length |
+-------------+------------+----------------+
| 16384 | 1 | 16384 |
+-------------+------------+----------------+
Stół nie urósł, jest całe niewykorzystane miejsce w tych 4 blokach, które ma. Jest jeden wiersz, co oznacza avg_row_length 16K. Wyraźnie absurdalny. Dodajmy kolejny wiersz.
mysql> insert into foo (id) VALUES (1);
mysql> select data_length, table_rows, avg_row_length from information_schema.tables where table_name = 'foo';
+-------------+------------+----------------+
| data_length | table_rows | avg_row_length |
+-------------+------------+----------------+
| 16384 | 2 | 8192 |
+-------------+------------+----------------+
Ta sama rzecz. 16 KB jest przydzielone dla tabeli, 2 wiersze wykorzystują tę przestrzeń. Absurdalny wynik 8K na rząd.
Gdy wstawiam coraz więcej wierszy, rozmiar tabeli pozostaje taki sam, zużywa coraz więcej przydzielonego miejsca, a avg_row_length
zbliża się do rzeczywistości.
mysql> select data_length, table_rows, avg_row_length from information_schema.tables where table_name = 'foo';
+-------------+------------+----------------+
| data_length | table_rows | avg_row_length |
+-------------+------------+----------------+
| 16384 | 2047 | 8 |
+-------------+------------+----------------+
Tutaj również zaczynamy widzieć table_rows
stają się niedokładne. Zdecydowanie wstawiłem 2048 wierszy.
Teraz, kiedy wstawiam więcej...
mysql> select data_length, table_rows, avg_row_length from information_schema.tables where table_name = 'foo';
+-------------+------------+----------------+
| data_length | table_rows | avg_row_length |
+-------------+------------+----------------+
| 98304 | 2560 | 38 |
+-------------+------------+----------------+
(Wstawiłem 512 wierszy i table_rows
z jakiegoś powodu wrócił do rzeczywistości)
MySQL zdecydował, że tabela potrzebuje więcej miejsca, więc została zmieniona i zabrała o wiele więcej miejsca na dysku. avg_row_length
po prostu znowu skoczył.
Zabrał o wiele więcej miejsca niż potrzebuje na te 512 wierszy, teraz jest to 96K lub 24 bloki 4K, przy założeniu, że będzie go później potrzebować. Minimalizuje to liczbę potencjalnie wolnych relokacji, które musi wykonać, i minimalizuje fragmentację dysku.
Nie oznacza to, że cała przestrzeń została wypełniona . Oznacza to po prostu, że MySQL uznał, że jest wystarczająco pełny, aby potrzebować więcej miejsca do wydajnego działania. Jeśli chcesz wiedzieć, dlaczego tak jest, zobacz, jak tabela mieszająca działa. Nie wiem, czy InnoDB używa tablicy mieszającej, ale obowiązuje zasada:niektóre struktury danych działają najlepiej, gdy jest trochę wolnego miejsca.
Dysk używany przez tabelę jest bezpośrednio powiązany z liczbą wierszy i typami kolumn w tabeli, ale dokładna formuła jest trudna do ustalenia i będzie się zmieniać z wersji na wersję MySQL. Najlepszym rozwiązaniem jest przeprowadzenie testów empirycznych i rezygnacja z tego, że nigdy nie uzyskasz dokładnej liczby.