- Eftersom
avg_row_length
ärdata_length / rows
.
data_length
är i princip den totala storleken på tabellen på disk . En InnoDB-tabell är mer än bara en lista med rader. Så det är det där extra omkostnaderna.
- Eftersom en InnoDB-rad är mer än data.
I likhet med ovan kommer varje rad med lite overhead. Så det kommer att öka storleken på en rad. En InnoDB-tabell är inte bara en lista över data som är ihophopade. Det behöver lite extra tomt utrymme för att fungera effektivt.
- Eftersom saker lagras på diskar i block och dessa block inte alltid är fulla.
Diskar lagrar saker i vanligtvis 4K, 8K eller 16K block . Ibland passar saker inte perfekt i dessa block, så du kan få en del tomma utrymme .
Som vi kommer att se nedan kommer MySQL att fördela tabellen i block. Och den kommer att allokera mycket mer än den behöver för att undvika att behöva växa tabellen (vilket kan vara långsamt och leda till diskfragmentering vilket gör saker ännu långsammare).
För att illustrera detta, låt oss börja med en tom tabell.
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 |
+-------------+------------+----------------+
Den använder 16K, eller fyra 4K-block, för att lagra ingenting. Den tomma tabellen behöver inte detta utrymme, men MySQL tilldelade det under antagandet att du kommer att lägga en massa data i den. Detta undviker att behöva göra en dyr omfördelning på varje skär.
Låt oss nu lägga till en rad.
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 |
+-------------+------------+----------------+
Bordet blev inte större, det finns allt det oanvända utrymmet inom de 4 blocken det har. Det finns en rad som betyder en avg_row_length på 16K. Klart absurt. Låt oss lägga till ytterligare en rad.
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 |
+-------------+------------+----------------+
Samma sak. 16K tilldelas för tabellen, 2 rader använder det utrymmet. Ett absurt resultat på 8K per rad.
När jag infogar fler och fler rader förblir tabellstorleken densamma, den använder upp mer och mer av sitt tilldelade utrymme och avg_row_length
kommer närmare verkligheten.
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 |
+-------------+------------+----------------+
Även här börjar vi se table_rows
bli felaktiga. Jag har definitivt infogat 2048 rader.
Nu när jag sätter in några till...
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 |
+-------------+------------+----------------+
(Jag infogade 512 rader och table_rows
har återgått till verkligheten av någon anledning)
MySQL beslutade att bordet behöver mer utrymme, så det ändrades storlek och tog en massa mer diskutrymme. avg_row_length
hoppade precis igen.
Den tog mycket mer utrymme än den behöver för de 512 raderna, nu är den 96K eller 24 4K-block, under antagandet att den kommer att behöva den senare. Detta minimerar hur många potentiellt långsamma omallokeringar den behöver göra och minimerar diskfragmentering.
Detta betyder inte att allt utrymme var fyllt . Det betyder bara att MySQL trodde att det var tillräckligt fullt för att behöva mer utrymme för att fungera effektivt. Om du vill ha en idé om varför det är så, titta på hur en hashtabell fungerar. Jag vet inte om InnoDB använder en hashtabell, men principen gäller:vissa datastrukturer fungerar bäst när det finns lite tomt utrymme.
Disken som används av en tabell är direkt relaterad till antalet rader och typer av kolumner i tabellen, men den exakta formeln är svår att ta reda på och kommer att ändras från version till version av MySQL. Det bästa är att göra några empiriska tester och säga upp dig själv att du aldrig kommer att få ett exakt antal.