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

Lunghezza media della riga maggiore del possibile

  • Perché avg_row_length è data_length / rows .

data_length è fondamentalmente la dimensione totale della tabella su disco . Una tabella InnoDB è più di un semplice elenco di righe. Quindi c'è quel sovraccarico extra.

  • Perché una riga InnoDB è più dei dati.

Simile a sopra, ogni riga viene fornita con un po' di sovraccarico. Quindi questo aumenterà la dimensione di una riga. Anche una tabella InnoDB non è solo un elenco di dati stipati insieme. Ha bisogno di un po' di spazio vuoto in più per funzionare in modo efficiente.

  • Perché le cose sono archiviate sui dischi in blocchi e quei blocchi non sono sempre pieni.

I dischi memorizzano le cose in blocchi di solito 4K, 8K o 16K . A volte le cose non si adattano perfettamente a quei blocchi, quindi puoi ottenere alcuni vuoti spazio .

Come vedremo di seguito, MySQL allocherà la tabella in blocchi. E allocherà molto più del necessario per evitare di dover aumentare il tavolo (che può essere lento e portare a frammentazione del disco il che rende le cose ancora più lente).

Per illustrare questo, iniziamo con una tabella vuota.

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

Utilizza 16K, o quattro blocchi 4K, per non memorizzare nulla. La tabella vuota non ha bisogno di questo spazio, ma MySQL l'ha allocata partendo dal presupposto che ci inserirai un sacco di dati. Questo evita di dover fare una costosa riallocazione su ogni inserto.

Ora aggiungiamo una riga.

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

Il tavolo non è diventato più grande, c'è tutto quello spazio inutilizzato all'interno di quei 4 blocchi che ha. C'è una riga che significa avg_row_length di 16K. Chiaramente assurdo. Aggiungiamo un'altra riga.

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

Stessa cosa. 16 KB sono allocati per la tabella, 2 righe che utilizzano quello spazio. Un risultato assurdo di 8K per riga.

Man mano che inserisco sempre più righe, la dimensione della tabella rimane la stessa, sta consumando sempre più spazio allocato e avg_row_length si avvicina alla realtà.

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

Anche qui iniziamo a vedere table_rows diventare impreciso. Ho sicuramente inserito 2048 righe.

Ora quando ne inserisco altri...

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

(Ho inserito 512 righe e table_rows è tornato alla realtà per qualche motivo)

MySQL ha deciso che la tabella ha bisogno di più spazio, quindi è stata ridimensionata e ha preso un sacco di spazio su disco in più. avg_row_length appena saltato di nuovo.

Ha preso molto più spazio del necessario per quelle 512 righe, ora sono 96K o 24 blocchi 4K, supponendo che ne avrà bisogno in seguito. Ciò riduce al minimo il numero di riallocazioni potenzialmente lente necessarie e riduce al minimo la frammentazione del disco.

Questo non significa che tutto lo spazio sia stato riempito . Significa solo che MySQL pensava che fosse abbastanza pieno da richiedere più spazio per funzionare in modo efficiente. Se vuoi un'idea del perché, guarda come una tabella hash opera. Non so se InnoDB utilizzi una tabella hash, ma si applica il principio:alcune strutture dati funzionano meglio quando c'è dello spazio vuoto.

Il disco utilizzato da una tabella è direttamente correlato al numero di righe e ai tipi di colonne nella tabella, ma la formula esatta è difficile da capire e cambierà da versione a versione di MySQL. La soluzione migliore è fare dei test empirici e rassegnarsi a non ottenere mai un numero esatto.