- Защото
avg_row_length
еdata_length / rows
.
data_length
е по същество общият размер на таблицата на диска . Таблицата на InnoDB е повече от просто списък с редове. Така че има допълнителни разходи.
- Защото един InnoDB ред е повече от данните.
Подобно на по-горе, всеки ред идва с малко режийни разходи. Така че това ще добави към размера на реда. Таблицата на InnoDB също не е просто списък с данни, натъпкани заедно. Има нужда от малко допълнително празно пространство, за да работи ефективно.
- Защото нещата се съхраняват на дискове в блокове и тези блокове не винаги са пълни.
Дисковете съхраняват нещата обикновено в 4K, 8K или 16K блокове . Понякога нещата не се вписват идеално в тези блокове, така че можете да получите нещо празно пространство .
Както ще видим по-долу, MySQL ще разпредели таблицата на блокове. И ще разпредели много повече, отколкото е необходимо, за да избегне необходимостта от увеличаване на таблицата (което може да бъде бавно и да доведе до фрагментиране на диска което прави нещата още по-бавни).
За да илюстрираме това, нека започнем с празна таблица.
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 |
+-------------+------------+----------------+
Той използва 16K или четири 4K блока, за да не съхранява нищо. Празната таблица не се нуждае от това пространство, но MySQL го разпредели с предположението, че ще поставите куп данни в нея. Това избягва необходимостта от скъпо преразпределяне на всяка вложка.
Сега нека добавим ред.
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 |
+-------------+------------+----------------+
Масата не стана по-голяма, има цялото това неизползвано пространство в рамките на тези 4 блока, които има. Има един ред, който означава avg_row_length от 16K. Явно абсурдно. Нека добавим още един ред.
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 |
+-------------+------------+----------------+
Същото нещо. 16K са разпределени за таблицата, 2 реда, използващи това пространство. Абсурден резултат от 8K на ред.
Докато вмъквам все повече и повече редове, размерът на таблицата остава същият, използва все повече и повече от разпределеното си пространство и avg_row_length
се доближава до реалността.
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 |
+-------------+------------+----------------+
Тук също започваме да виждаме table_rows
стават неточни. Определено вмъкнах 2048 реда.
Сега, когато вмъкна още...
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 |
+-------------+------------+----------------+
(Вмъкнах 512 реда и table_rows
се върна към реалността по някаква причина)
MySQL реши, че таблицата се нуждае от повече място, така че беше преоразмерена и грабна куп повече дисково пространство. avg_row_length
просто скочих отново.
Той грабна много повече място, отколкото му е необходимо за тези 512 реда, сега е 96K или 24 4K блока, с допускането, че ще има нужда от него по-късно. Това свежда до минимум колко потенциално бавни преразпределения трябва да направи и свежда до минимум фрагментацията на диска.
Това не означава, че цялото пространство е запълнено . Това просто означава, че MySQL смята, че е достатъчно пълен, за да има нужда от повече пространство, за да работи ефективно. Ако искате идея защо е така, разгледайте как една хеш таблица действа. Не знам дали InnoDB използва хеш таблица, но важи принципът:някои структури от данни работят най-добре, когато има празно пространство.
Дискът, използван от таблица, е пряко свързан с броя на редовете и типовете колони в таблицата, но точната формула е трудна за установяване и ще се променя от версия на версия на MySQL. Най-добре е да направите някои емпирични тестове и да се примирите, че никога няма да получите точен брой.