2010-05-26 12 views
7

Sto cercando di capire i requisiti di archiviazione per diversi motori di archiviazione. Ho questa tabella:Perché la dimensione della tabella InnoDB è molto più grande del previsto?

CREATE TABLE `mytest` (
    `num1` int(10) unsigned NOT NULL, 
    KEY `key1` (`num1`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

Quando inserisco alcuni valori e quindi eseguire show table status; ricevo il seguente:

 
+----------------+--------+---------+------------+---------+----------------+-------------+------------------+--------------+-----------+----------------+---------------------+---------------------+------------+-------------------+----------+----------------+---------+ 
| Name   | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time   | Update_time   | Check_time | Collation   | Checksum | Create_options | Comment | 
+----------------+--------+---------+------------+---------+----------------+-------------+------------------+--------------+-----------+----------------+---------------------+---------------------+------------+-------------------+----------+----------------+---------+ 
| mytest   | InnoDB |  10 | Compact | 1932473 |    35 | 67715072 |    0 |  48840704 | 4194304 |   NULL | 2010-05-26 11:30:40 | NULL    | NULL  | latin1_swedish_ci |  NULL |    |   | 

Avviso avg_row_length è 35. Sono sconcertato che InnoDB non fare un uso migliore degli spazi quando sto solo memorizzando un numero intero non nullable.

Ho eseguito questo stesso test su myISAM e per impostazione predefinita myISAM utilizza 7 byte per riga su questa tabella. Quando corro

ALTER TABLE mytest MAX_ROWS=50000000, AVG_ROW_LENGTH = 4; 

causa che myISAM utilizza correttamente le righe di 5 byte.

Quando eseguo la stessa istruzione ALTER TABLE per InnoDB, avg_row_length non cambia.

Perché sarebbe necessaria una lunghezza avg_row_ così grande quando si memorizza solo un int con unsigned a 4 byte?

+0

Ho appena letto che InnoDB utilizza lo spazio tabelle sia per i dati che per l'indice. questo ha senso e sembra che questo sarebbe il motivo per cui sto vedendo un così grande avg_row_length ... forse. Ho anche scoperto che ogni nodo foglia memorizza l'ID della transazione e il puntatore del rollback. Beh, non sto facendo uso di transazioni di per sé e quindi non ho alcuna utilità per questi dati. c'è un modo per non memorizzare questi valori? In qualsiasi modo posso usare InnoDB ma fare un uso un po 'migliore dello spazio di archiviazione? grazie! –

+0

@alessandro: sì, il supporto alle transazioni aggiunge un po 'di overhead. Il fatto che tu non stia facendo uso di transazioni non significa che non vengano utilizzate: ad esempio, un thread ucciso durante un'operazione lunga 'UPDATE' eseguirà il rollback correttamente in 'InnoDB' ma non in' MyISAM'. Il supporto delle transazioni è il punto principale dell'utilizzo di 'InnoDB', se non ne hai bisogno, usa' MyISAM'. – Quassnoi

+0

@Quassnoi: ho avuto l'impressione che MyISAM non sia "maturo" o pronto per la produzione come InnoDB ... forse è una paura infondata. Ci sono disagi che MyISAM mette in campo quando si tratta di eseguire il backup dei database oltre al fatto che MyISAM richiede un blocco totale del tavolo per garantire la coerenza. Non ho bisogno di transazioni e conserverò molti dati. Ci sono problemi noti con MyISAM che potrebbero causare il mancato utilizzo? –

risposta

10

InnoDB le tabelle sono raggruppate, ovvero tutti i dati sono contenuti in un B-Tree con PRIMARY KEY come chiave e tutte le altre colonne come carico utile.

Poiché non si definisce un PRIMARY KEY esplicito, InnoDB utilizza una colonna nascosta di 6 byte per ordinare i record.

Questo e l'overhead dell'organizzazione B-Tree (con blocchi extra non a livello di foglia) richiedono più spazio di sizeof(int) * num_rows.

0

In aggiunta alla risposta molto bella di Quassnoi, è consigliabile provarlo utilizzando un set di dati significativo.

Quello che farei è caricare 1M di file di dati di produzione simulati, quindi misurare la dimensione della tabella e utilizzarla come guida.

Questo è ciò che I've done in the past anyway

+0

Sì, grazie MarkR, l'ho fatto con un set di dati di 50 milioni di righe. InnoDB ha utilizzato più di 3 volte più spazio in 3GIGs –

+0

In base al mio studio (vedi link sopra), questo è tipico; puoi usare meno spazio usando il plugin e attivando la compressione. Vedi il mio post sul blog per alcuni dati. – MarkR

2

Ecco qualche informazione in più che potrebbe risultare utile.

InnoDB assegna i dati in termini di pagine da 16 KB, quindi 'MOSTRA TABELLA STATO' fornirà numeri gonfiati per le dimensioni della riga se si dispone solo di poche righe e la tabella è < 16 K totale. (Ad esempio, con 4 righe la dimensione della riga media ritorna come 4096.)

I 6 byte aggiuntivi per riga per la chiave primaria "invisibile" sono un punto cruciale quando lo spazio è una grande considerazione. Se la tabella è solo una colonna, che è la colonna ideale per rendere la chiave primaria, assumendo i valori in essa sono unici:

CREATE TABLE `mytest2` 
     (`num1` int(10) unsigned NOT NULL primary key) 
ENGINE=InnoDB DEFAULT CHARSET=latin1; 

Utilizzando una chiave primaria come questo:

  1. alcun indice o La clausola KEY è necessaria, perché non hai un indice secondario. Il formato organizzato in base all'indice delle tabelle InnoDB offre una rapida ricerca basata sul valore della chiave primaria gratuitamente.
  2. Non si finisce con un'altra copia dei dati della colonna NUM1, che è ciò che accade quando tale colonna viene indicizzata in modo esplicito.
  3. Non si finisce con un'altra copia dei valori di chiave primaria invisibile a 6 byte. I valori delle chiavi primarie sono duplicati in ciascun indice secondario. (Questo è anche il motivo per cui probabilmente non vuoi 10 indici su una tabella con 10 colonne, e probabilmente non vuoi una chiave primaria che combina diverse colonne o una lunga colonna di stringhe.)

Quindi, in generale, attenersi solo a una chiave primaria significa meno dati associati alla tabella + indici. Per avere un'idea di dimensione complessiva dei dati, mi piace correre con

set innodb_file_per_table = 1; 

ed esaminare la dimensione dei dati/banca dati file /*table*.ibd. Ogni file .ibd contiene i dati per una tabella InnoDB e tutti gli indici associati.

di costruire rapidamente un grande tavolo per le prove, io di solito eseguire un'istruzione in questo modo:

insert into mytest 
select * from mytest; 

che raddoppia la quantità di dati ogni volta. Nel caso della tabella singola colonna utilizzando una chiave primaria, poiché i valori dovevano essere unico, ho utilizzato una variante per mantenere i valori dalla collisione tra loro:

insert into mytest2 
select num1 + (select count(*) from mytest2) from mytest2; 

questo modo, ho potuto riduci la dimensione della riga media a 25. L'overhead dello spazio si basa sull'assunto sottostante che vuoi avere una ricerca rapida per le singole righe usando un meccanismo a puntatore, e la maggior parte delle tabelle avrà una colonna i cui valori fungono da puntatori (cioè il primario chiave) oltre alle colonne con dati reali che vengono sommati, mediati e visualizzati.

+0

Ottime informazioni qui, grazie per aver condiviso. – dkamins

Problemi correlati