- Protože
avg_row_length
jedata_length / rows
.
data_length
je v podstatě celková velikost tabulky na disku . Tabulka InnoDB je více než jen seznam řádků. Takže je tu další režie.
- Protože řádek InnoDB je více než data.
Podobně jako výše, každý řádek přichází s určitou režií. Takže to přidá na velikosti řádku. Tabulka InnoDB také není jen seznam dat nacpaných dohromady. Potřebuje trochu prázdného místa navíc, aby fungoval efektivně.
- Protože věci jsou na discích uloženy v blocích a tyto bloky nejsou vždy plné.
Disky ukládají věci obvykle v 4K, 8K nebo 16K blocích . Někdy věci do těchto bloků dokonale nezapadají, takže můžete získat nějaké prázdné prostor .
Jak uvidíme níže, MySQL bude tabulku alokovat v blocích. A bude přidělovat mnohem více, než je potřeba, aby nebylo nutné zvětšovat tabulku (což může být pomalé a vést k fragmentace disku což dělá věci ještě pomalejší).
Abychom to ilustrovali, začněme s prázdnou tabulkou.
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 |
+-------------+------------+----------------+
K uložení ničeho používá 16K nebo čtyři 4K bloky. Prázdná tabulka tento prostor nepotřebuje, ale MySQL ho přidělilo za předpokladu, že do něj vložíte hromadu dat. Tím se vyhnete nutnosti provádět drahé přerozdělení každé vložky.
Nyní přidáme řádek.
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ůl se nezvětšil, v těch 4 blocích je všechno nevyužité místo, které má. Je zde jeden řádek, který znamená průměrnou délku 16 kB. Jasně absurdní. Pojďme přidat další řádek.
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 |
+-------------+------------+----------------+
Stejná věc. Pro tabulku je přiděleno 16 kB, tento prostor využívají 2 řádky. Absurdní výsledek 8 000 na řádek.
Jak vkládám další a další řádky, velikost tabulky zůstává stejná, zabírá stále více svého přiděleného místa a avg_row_length
se blíží realitě.
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 |
+-------------+------------+----------------+
Zde také začínáme vidět table_rows
stát se nepřesným. Určitě jsem vložil 2048 řádků.
Teď, když vložím další...
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 |
+-------------+------------+----------------+
(Vložil jsem 512 řádků a table_rows
se z nějakého důvodu vrátilo do reality)
MySQL se rozhodlo, že tabulka potřebuje více místa, takže byla změněna velikost a zabrala mnohem více místa na disku. avg_row_length
znovu skočil.
Zabralo to mnohem víc místa, než potřebuje pro těch 512 řádků, teď je to 96K nebo 24 4K bloků, za předpokladu, že to bude potřebovat později. To minimalizuje počet potenciálně pomalých realokací, které potřebuje provést, a minimalizuje fragmentaci disku.
To neznamená, že byl celý prostor zaplněn . Znamená to jen, že MySQL si myslelo, že je dostatečně plné, aby potřebovalo více místa, aby fungovalo efektivně. Pokud chcete mít představu, proč tomu tak je, podívejte se, jak hashovací tabulka provozuje. Nevím, jestli InnoDB používá hashovací tabulku, ale platí zásada:některé datové struktury fungují nejlépe, když je tam nějaké prázdné místo.
Disk používaný tabulkou přímo souvisí s počtem řádků a typů sloupců v tabulce, ale přesný vzorec je obtížné zjistit a bude se měnit verze od verze MySQL. Nejlepším řešením je provést nějaké empirické testování a rezignovat na to, že nikdy nezískáte přesné číslo.