2015-12-22 6 views
5

Ho bisogno di ridurre la dimensione del database MySQL. Ho ricodificato alcune informazioni che hanno barrato ';' e ':' dalla colonna sources (riduzione del 10% circa). Dopo averlo fatto, la dimensione della tabella è esattamente la stessa di prima. Come è possibile? Sto usando il motore MyISAM.Perché la dimensione della tabella MyISAM MySQL è la stessa dopo aver rimosso alcuni dati dalla colonna VARCHAR?

btw: Sfortunatamente, non riesco a comprimere le tabelle con myisampack.

mysql> INSERT INTO test SELECT protid1, protid2, CS, REPLACE(REPLACE(sources, ':', ''), ';', '') FROM homologs_9606; 
Query OK, 41917131 rows affected (4 min 11.30 sec) 
Records: 41917131 Duplicates: 0 Warnings: 0 

mysql> select TABLE_NAME name, ROUND(TABLE_ROWS/1e6, 3) 'million rows', ROUND(DATA_LENGTH/power(2,30), 3) 'data GB', ROUND(INDEX_LENGTH/power(2,30), 3) 'index GB' from information_schema.TABLES WHERE TABLE_NAME IN ('homologs_9606', 'test') ORDER BY TABLE_ROWS DESC LIMIT 10; 
+---------------+--------------+---------+----------+ 
| name   | million rows | data GB | index GB | 
+---------------+--------------+---------+----------+ 
| test   |  41.917 | 0.857 | 1.075 | 
| homologs_9606 |  41.917 | 0.887 | 1.075 | 
+---------------+--------------+---------+----------+ 
2 rows in set (0.01 sec) 

mysql> select * from homologs_9606 limit 10; 
+---------+---------+-------+--------------------------------+ 
| protid1 | protid2 | CS | sources      | 
+---------+---------+-------+--------------------------------+ 
| 5635338 | 1028608 | 0.000 | 10:,1       | 
| 5644385 | 1028611 | 0.947 | 5:1,1;8:0.943,35;10:1,1;11:1,1 | 
| 5652325 | 1028611 | 0.947 | 5:1,1;8:0.943,35;10:1,1;11:1,1 | 
| 5641128 | 1028612 | 1.000 | 8:1,10       | 
| 5636414 | 1028616 | 0.038 | 8:0.038,104;10:,1    | 
| 5636557 | 1028616 | 0.000 | 8:,4       | 
| 5637419 | 1028616 | 0.011 | 5:,1;8:0.011,91;10:,1   | 
| 5641196 | 1028616 | 0.080 | 5:1,1;8:0.074,94;10:,1;11:,4 | 
| 5642914 | 1028616 | 0.000 | 8:,3       | 
| 5643778 | 1028616 | 0.056 | 8:0.057,70;10:,1    | 
+---------+---------+-------+--------------------------------+ 
10 rows in set (4.55 sec) 

mysql> select * from test limit 10; 
+---------+---------+-------+-------------------------+ 
| protid1 | protid2 | CS | sources     | 
+---------+---------+-------+-------------------------+ 
| 5635338 | 1028608 | 0.000 | 10,1     | 
| 5644385 | 1028611 | 0.947 | 51,180.943,35101,1111,1 | 
| 5652325 | 1028611 | 0.947 | 51,180.943,35101,1111,1 | 
| 5641128 | 1028612 | 1.000 | 81,10     | 
| 5636414 | 1028616 | 0.038 | 80.038,10410,1   | 
| 5636557 | 1028616 | 0.000 | 8,4      | 
| 5637419 | 1028616 | 0.011 | 5,180.011,9110,1  | 
| 5641196 | 1028616 | 0.080 | 51,180.074,9410,111,4 | 
| 5642914 | 1028616 | 0.000 | 8,3      | 
| 5643778 | 1028616 | 0.056 | 80.057,7010,1   | 
+---------+---------+-------+-------------------------+ 
10 rows in set (0.00 sec) 

mysql> describe test; 
+---------+------------------+------+-----+---------+-------+ 
| Field | Type    | Null | Key | Default | Extra | 
+---------+------------------+------+-----+---------+-------+ 
| protid1 | int(10) unsigned | YES | PRI | NULL |  | 
| protid2 | int(10) unsigned | YES | PRI | NULL |  | 
| CS  | float(4,3)  | YES |  | NULL |  | 
| sources | varchar(100)  | YES |  | NULL |  | 
+---------+------------------+------+-----+---------+-------+ 
4 rows in set (0.00 sec) 

mysql> describe homologs_9606; 
+---------+------------------+------+-----+---------+-------+ 
| Field | Type    | Null | Key | Default | Extra | 
+---------+------------------+------+-----+---------+-------+ 
| protid1 | int(10) unsigned | NO | PRI | 0  |  | 
| protid2 | int(10) unsigned | NO | PRI | 0  |  | 
| CS  | float(4,3)  | YES |  | NULL |  | 
| sources | varchar(100)  | YES |  | NULL |  | 
+---------+------------------+------+-----+---------+-------+ 
4 rows in set (0.00 sec) 

MODIFICA1: aggiunta lunghezza colonna media.

mysql> select AVG(LENGTH(sources)) from test; 
+----------------------+ 
| AVG(LENGTH(sources)) | 
+----------------------+ 
|    5.2177 | 
+----------------------+ 
1 row in set (10.04 sec) 

mysql> select AVG(LENGTH(sources)) from homologs_9606; 
+----------------------+ 
| AVG(LENGTH(sources)) | 
+----------------------+ 
|    6.8792 | 
+----------------------+ 
1 row in set (9.95 sec) 

EDIT2: ho potuto mettere a nudo qualche altra MB impostando NOT NULL a tutte le colonne.

mysql> drop table test 
Query OK, 0 rows affected (0.42 sec) 

mysql> CREATE table test (protid1 INT UNSIGNED NOT NULL DEFAULT '0', protid2 INT UNSIGNED NOT NULL DEFAULT '0', CS FLOAT(4,3) NOT NULL DEFAULT '0', sources VARCHAR(100) NOT NULL DEFAULT '0', PRIMARY KEY (protid1, protid2), KEY `idx_protid2` (protid2)) ENGINE=MyISAM CHARSET=ascii; 
Query OK, 0 rows affected (0.06 sec) 

mysql> INSERT INTO test SELECT protid1, protid2, CS, REPLACE(REPLACE(sources, ':', ''), ';', '') FROM homologs_9606; 
Query OK, 41917131 rows affected (2 min 7.84 sec) 

mysql> select TABLE_NAME name, ROUND(TABLE_ROWS/1e6, 3) 'million rows', ROUND(DATA_LENGTH/power(2,30), 3) 'data GB', ROUND(INDEX_LENGTH/power(2,30), 3) 'index GB' from information_schema.TABLES WHERE TABLE_NAME IN ('homologs_9606', 'test'); 
Records: 41917131 Duplicates: 0 Warnings: 0 

+---------------+--------------+---------+----------+ 
| name   | million rows | data GB | index GB | 
+---------------+--------------+---------+----------+ 
| homologs_9606 |  41.917 | 0.887 | 1.075 | 
| test   |  41.917 | 0.842 | 1.075 | 
+---------------+--------------+---------+----------+ 
2 rows in set (0.02 sec) 
+1

Avete eseguito 'OTTIMIZZA TABELLA'? – Jaco

+0

sì, la dimensione è la stessa. – Leszek

+0

È possibile includere AVG (LENGTH (fonti)) per entrambe le tabelle? E anche il set di caratteri per ogni tabella ('SHOW CREATE TABLE tablename' è migliore di' DESCRIBE tablename') –

risposta

2

Non sono esattamente la stessa cosa. La query mostra chiaramente che test è di circa 30 MB di dimensioni inferiori a homologs_9606:

+---------------+--------------+---------+ 
| name   | million rows | data GB | 
+---------------+--------------+---------+ 
| test   |  41.917 | 0.857 | <-- 0.857 < 0.887 
| homologs_9606 |  41.917 | 0.887 | 
+---------------+--------------+---------+ 

Quanto stoccaggio dovremmo aspettarci per la vostra tavola? Cerchiamo di controllare Data Type Storage Requirements:

INTEGER(10): 4 bytes 
FLOAT(4): 4 bytes 
VARCHAR(100): L+1 

dove L è il numero di byte di caratteri, che di solito è un byte per carattere, ma a volte di più se si utilizza un set di caratteri Unicode.

le righe in media dovranno:

INTEGER + INTEGER + FLOAT + VARCHAR = 
4 + 4 + 4 + (L + 1) = L + 13 bytes 

possiamo dedurre la vostra L media originale come (0.887*1024^3/41917131) - 13 = 9.72. Dici di aver spogliato del 10% da sources, il che significa che la tua nuova L è 9.72*0.9 = 8.75. Che dà un nuovo requisito di archiviazione totale previsto di ((8.75 + 13) * 41917131)/1024^3 = 0.849 GB

Ho il sospetto che la differenza (tra 0,849 e 0,857) potrebbe essere dovuto al fatto che test hanno due colonne impostato come nullable homologs_9606 non hanno, ma io do not know enough sulla Motore MyISAM per calcolare esattamente questo. Posso comunque indovinare! Almeno occorrerebbe 1 bit per colonna per riga per memorizzare uno stato NULL, che nel tuo caso significa due bit per riga o 2*41917131 = 83834262 bits = 10 479 283 bytes = 0.010 GB. Il totale 0.849+0.010 = 0.859 spara leggermente sopra l'obiettivo (circa 2 MB di troppo). Ma ho fatto alcuni arrotondamenti e la tua cifra del 10% è anche una stima, quindi sono sicuro che il resto è perso nella traduzione.

Un altro motivo potrebbe essere se si utilizza un set di caratteri Unicode su sources in test, nel qual caso alcuni caratteri possono utilizzare più di un byte ciascuno, ma dal momento che le colonne nullable sembra tenere conto di tutto quello che non credo che questo è il caso per il tuo tavolo.

Sommario

  • I suoi due tabelle non sono della stessa dimensione, differiscono da 30 MB.
  • La dimensione della nuova tabella è attorno alle dimensioni previste.
  • È possibile risparmiare un po 'di spazio nel nuovo tavolo creando protid1 e protid2 nelle colonne NOT NULL.
+0

Grazie per la risposta molto premurosa, Emil! Imposterò valori NOT NULL. – Leszek

+0

So molto poco dei tuoi dati, ma potresti prendere in considerazione l'ipotesi di impostare le colonne intere su MEDIUMINT * se * non ti servirà l'intervallo extra (vedi [Tipi interi] (https://dev.mysql.com/doc/ refman/5.7/it/integer-types.html) per la gamma esatta). Ciò farebbe risparmiare circa 40 MB per colonna. –

+0

Buon suggerimento. Lo stavo provando prima, ma il protid1/2 potrebbe superare il massimo MEDIUMINT nel prossimo futuro. Ad ogni modo, utilizzando MEDIUMINT si libera un altro 19 Mb (0,823 GB) – Leszek

0

La "tabella" è memorizzata in un file .MYD. Questo file sostituirà mai a causa di UPDATEs o DELETEs. SHOW TABLE STATUS (o la query equivalente in information_schema) potrebbe mostrare Data_length restringimento, ma l'incremento Data_free aumenterà.

È possibile restringere il file .MYD facendo OPTIMIZE TABLE. Ma questo copierà la tabella, quindi necessiterà di ulteriore spazio su disco durante il processo. E questa azione vale solo raramente.

La modifica a NOT NULL non può liberare spazio se si hanno molti valori null - "" richiede 1 o 2 byte per un VARCHAR a causa della lunghezza. (E il tuo codice potrebbe dover gestire "" diversamente da NULL.)

Lo spazio occupato per ogni riga è in realtà di 1 byte in più rispetto a prima menzionato - questo byte gestisce sapere se la riga esiste o è l'inizio di un buco .

Per i campi di testo di grandi dimensioni, mi piace farlo per risparmiare spazio. (Questo vale sia per MyISAM che per InnoDB.) Comprime il testo e lo memorizza in una colonna BLOB (anziché TEXT). Per la maggior parte del testo, si tratta di un restringimento 3: 1. Ci vuole un po 'di codice in più e tempo di CPU nel client, ma si risparmia un sacco di I/O nel server. Spesso il risultato netto è "più veloce". Non lo userei per il varchar che hai; Lo farei solo su colonne più grandi di, diciamo, in media 50 caratteri.

Torna alla domanda iniziale. Sembra che ci fossero solo circa 30 milioni di punti e punto e virgola nell'intera tabella. Potrebbe essere che le prime 10 righe non siano rappresentative?

+0

Se si legge lo schema incluso nella domanda, si vedrà che la tabella originale aveva solo i campi NOT NULL quindi è possibile cambiarli in NOT NULL nella nuova tabella senza perdere alcun dato. –

Problemi correlati