sql >> Database >  >> RDS >> Mysql

Gemiddelde rijlengte hoger dan mogelijk

  • Omdat avg_row_length is data_length / rows .

data_length is in feite de totale grootte van de tabel op schijf . Een InnoDB-tabel is meer dan alleen een lijst met rijen. Er is dus die extra overhead.

  • Omdat een InnoDB-rij meer is dan de gegevens.

Net als hierboven, heeft elke rij wat overhead. Dus dat wordt toegevoegd aan de grootte van een rij. Een InnoDB-tabel is ook niet alleen een lijst met op elkaar gepropte gegevens. Het heeft wat extra lege ruimte nodig om efficiënt te werken.

  • Omdat dingen in blokken op schijven worden opgeslagen en die blokken niet altijd vol zijn.

Schijven slaan dingen meestal op in 4K, 8K of 16K blokken . Soms passen dingen niet perfect in die blokken, dus je kunt leeg krijgen spatie .

Zoals we hieronder zullen zien, zal MySQL de tabel in blokken toewijzen. En het zal veel meer toewijzen dan nodig is om te voorkomen dat de tafel moet groeien (wat traag kan zijn en kan leiden tot schijffragmentatie waardoor alles nog langzamer gaat).

Om dit te illustreren, laten we beginnen met een lege tafel.

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 |
+-------------+------------+----------------+

Het gebruikt 16K, of vier 4K-blokken, om niets op te slaan. De lege tabel heeft deze ruimte niet nodig, maar MySQL heeft het toegewezen in de veronderstelling dat je er een heleboel gegevens in gaat plaatsen. Dit vermijdt een dure hertoewijzing op elke insert.

Laten we nu een rij toevoegen.

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 |
+-------------+------------+----------------+

De tafel is niet groter geworden, er is al die ongebruikte ruimte binnen die 4 blokken die het heeft. Er is één rij die een avg_row_length van 16K betekent. Duidelijk absurd. Laten we nog een rij toevoegen.

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 |
+-------------+------------+----------------+

Hetzelfde. 16K is toegewezen voor de tafel, 2 rijen die die ruimte gebruiken. Een absurd resultaat van 8K per rij.

Naarmate ik meer en meer rijen invoeg, blijft de grootte van de tabel hetzelfde, verbruikt het steeds meer van de toegewezen ruimte en de avg_row_length komt dichter bij de werkelijkheid.

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 |
+-------------+------------+----------------+

Ook hier beginnen we table_rows te zien onnauwkeurig worden. Ik heb zeker 2048 rijen ingevoegd.

Als ik nu wat meer invoeg...

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 |
+-------------+------------+----------------+

(Ik heb 512 rijen ingevoegd en table_rows is om de een of andere reden teruggekeerd naar de realiteit)

MySQL besloot dat de tabel meer ruimte nodig had, dus het werd verkleind en pakte een hoop meer schijfruimte. avg_row_length net weer gesprongen.

Het pakte veel meer ruimte dan het nodig heeft voor die 512 rijen, nu zijn het 96K of 24 4K blokken, in de veronderstelling dat het het later nodig zal hebben. Dit minimaliseert het aantal potentieel trage hertoewijzingen dat het moet doen en minimaliseert schijffragmentatie.

Dit betekent niet dat al die ruimte vol was . Het betekent alleen dat MySQL dacht dat het vol genoeg was om meer ruimte nodig te hebben om efficiënt te werken. Als je een idee wilt hebben waarom dat zo is, kijk dan hoe een hashtabel werkt. Ik weet niet of InnoDB een hash-tabel gebruikt, maar het principe is van toepassing:sommige datastructuren werken het beste als er wat lege ruimte is.

De schijf die door een tabel wordt gebruikt, is direct gerelateerd aan het aantal rijen en typen kolommen in de tabel, maar de exacte formule is moeilijk te achterhalen en zal van versie tot versie van MySQL veranderen. Je kunt het beste wat empirische tests doen en jezelf neerleggen dat je nooit een exact aantal zult krijgen.




  1. sql server subquery met een door komma's gescheiden resultatenset

  2. Trade-offs in Hot Standby-implementaties

  3. MySQL-tabel met onjuist gecodeerde gegevens converteren naar UTF-8

  4. Is een enkele SQL Server-instructie atomair en consistent?