sql >> Database teknologi >  >> RDS >> Mysql

Gennemsnitlig rækkelængde højere end muligt

  • Fordi avg_row_length er data_length / rows .

data_length er dybest set den samlede størrelse af tabellen på disken . En InnoDB-tabel er mere end blot en liste over rækker. Så der er det ekstra overhead.

  • Fordi en InnoDB-række er mere end dataene.

I lighed med ovenfor kommer hver række med nogle overhead. Så det vil føje til størrelsen på en række. En InnoDB-tabel er heller ikke kun en liste over data, der er proppet sammen. Den har brug for lidt ekstra tom plads for at arbejde effektivt.

  • Fordi ting er gemt på diske i blokke, og disse blokke er ikke altid fulde.

Diske gemmer ting i normalt 4K, 8K eller 16K blokke . Nogle gange passer tingene ikke perfekt i de blokke, så du kan få nogle tomme plads .

Som vi vil se nedenfor, vil MySQL tildele tabellen i blokke. Og det kommer til at allokere meget mere, end det har brug for for at undgå at skulle vokse tabellen (hvilket kan være langsomt og føre til diskfragmentering hvilket gør tingene endnu langsommere).

For at illustrere dette, lad os starte med en tom tabel.

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 bruger 16K, eller fire 4K-blokke, til at gemme ingenting. Den tomme tabel har ikke brug for denne plads, men MySQL tildelte den ud fra den antagelse, at du vil lægge en masse data i den. Dette undgår at skulle lave en dyr omfordeling på hvert skær.

Lad os nu tilføje en række.

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 ikke større, der er al den ubrugte plads inden for de 4 blokke, det har. Der er én række, hvilket betyder en gennemsnitlig_række_længde på 16K. Klart absurd. Lad os tilføje endnu en række.

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

Samme ting. 16K er allokeret til tabellen, 2 rækker bruger denne plads. Et absurd resultat på 8K pr. række.

Efterhånden som jeg indsætter flere og flere rækker, forbliver tabelstørrelsen den samme, den bruger mere og mere af sin tildelte plads, og avg_row_length kommer tættere på virkeligheden.

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

Også her begynder vi at se table_rows blive unøjagtig. Jeg har bestemt indsat 2048 rækker.

Når jeg nu indsætter nogle flere...

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

(Jeg indsatte 512 rækker og table_rows er vendt tilbage til virkeligheden af ​​en eller anden grund)

MySQL besluttede, at bordet har brug for mere plads, så størrelsen blev ændret og fik en masse mere diskplads. avg_row_length sprang lige igen.

Den tog meget mere plads, end den har brug for til de 512 rækker, nu er den 96K eller 24 4K blokke, ud fra den antagelse, at den får brug for det senere. Dette minimerer, hvor mange potentielt langsomme omallokeringer, den skal udføre, og minimerer diskfragmentering.

Dette betyder ikke, at al den plads var udfyldt . Det betyder bare, at MySQL troede, at den var fuld nok til at have brug for mere plads for at køre effektivt. Hvis du vil have en idé om, hvorfor det er sådan, skal du undersøge, hvordan en hash-tabel fungerer. Jeg ved ikke, om InnoDB bruger en hash-tabel, men princippet gælder:nogle datastrukturer fungerer bedst, når der er noget tomt rum.

Disken, der bruges af en tabel, er direkte relateret til antallet af rækker og typer af kolonner i tabellen, men den nøjagtige formel er svær at finde ud af og vil ændre sig fra version til version af MySQL. Dit bedste bud er at lave nogle empiriske test og sige op, at du aldrig får et nøjagtigt tal.




  1. MySQL rækkefølge efter felt i Eloquent

  2. Store .PDF-filer uploades ikke til MySQL-databasen som medium BLOB via PHP, filer under 2 MB fungerer fint

  3. Hvordan kopierer man data fra en tabel til en anden ny tabel i MySQL?

  4. Indsamlingsmetode:FØRSTE OG NÆSTE funktioner i Oracle-databasen