L'ho affrontato in StackOverflow nell'ottobre 2010 .
Tieni presente il file più occupato nell'infrastruttura InnoDB: / var / lib / mysql / ibdata1
Questo file contiene normalmente quattro tipi di informazioni
- Dati tabella
- Indici delle tabelle
- Dati MVCC (Multiversioning Concurrency Control)
- Metadati tabella (elenco di ID spazio tabelle)
L'esecuzione OPTIMIZE TABLE
su una tabella InnoDB memorizzata in ibdata1 fa due cose:
- Rende i dati e gli indici della tabella contigui all'interno di ibdata1, quindi l'accesso più veloce
- Fa crescere ibdata1 perché i dati contigui e le pagine di indice vengono aggiunti a ibdata1
Sebbene sia possibile separare i dati delle tabelle e gli indici delle tabelle da ibdata1 e gestirli in modo indipendente utilizzando innodb_file_per_table , il grande spazio vuoto su ibdata1 semplicemente non scompare e non può essere recuperato. Devi fare di più.
Per ridurre ibdata1 una volta per tutte , devi fare quanto segue:
1) MySQLDump di tutti i database in un file di testo SQL (chiamalo /root/SQLData.sql)
2) Eliminare tutti i database (tranne lo schema mysql)
3) Spegnere mysql
4) Aggiungi le seguenti righe a /etc/my.cnf
[mysqld]
innodb_file_per_table
innodb_flush_method=O_DIRECT
innodb_log_file_size=1G
innodb_buffer_pool_size=4G
Sidenote: qualunque sia il tuo set per innodb_buffer_pool_size, assicurati che innodb_log_file_size sia il 25% di innodb_buffer_pool_size.
5) Elimina ibdata1, ib_logfile0 e ib_logfile1
A questo punto, dovrebbe esserci solo lo schema mysql in / var / lib / mysql
6) Riavvia mysql
Ciò ricrea ibdata1 a 10 o 18 MB (a seconda della versione di MySQL), ib_logfile0 e ib_logfile1 a 1G ciascuno
7) Ricarica /root/SQLData.sql in mysql
ibdata1 crescerà ma conterrà solo metadati di tabella. In effetti, crescerà molto lentamente nel corso degli anni. L'unico modo in cui la crescita di ibdata1 è rapida è se si dispone di uno o più dei seguenti:
- Un sacco di DDL (
CREATE TABLE
, DROP TABLE
, ALTER TABLE
)
- Molte transazioni
- Molte modifiche da impegnare per transazione
Ogni tabella InnoDB esiste al di fuori di ibdata1
Supponiamo di avere una tabella InnoDB denominata mydb.mytable. Se vai in / var / lib / mysql / mydb, vedrai due file che rappresentano la tabella
- mytable.frm (intestazione del motore di archiviazione)
- mytable.ibd (Home dei dati delle tabelle e degli indici delle tabelle per mydb.mytable)
ibdata1 non conterrà più dati e indici InnoDB.
Con l'opzione innodb_file_per_table in /etc/my.cnf, puoi eseguire OPTIMIZE TABLE mydb.mytable;
e il file /var/lib/mysql/mydb/mytable.ibd si ridurrà effettivamente.
L'ho fatto molte volte nella mia carriera come DBA MySQL
In effetti, la prima volta che l'ho fatto, ho compresso un file ibdata1 da 50 GB in 500 MB.
Provaci. Se hai ulteriori domande al riguardo, inviami un'e-mail. Fidati di me. Funzionerà a breve e lungo termine !!!
AGGIORNAMENTO 2012-04-19 09:23 EDT
Dopo aver eseguito i passaggi precedenti, come è possibile determinare quali tabelle devono essere deframmentate? È possibile scoprirlo, ma avrai lo script.
Ecco un esempio: supponiamo di avere la tabella mydb.mytable
. Con innodb_file_per_table abilitato, hai il file /var/lib/mysql/mydb/mytable.ibd
Dovrai recuperare due numeri
FILESIZE DAL SO: È possibile verificare la dimensione del file dal SO in questo modo
ls -l /var/lib/mysql/mydb/mytable.ibd | awk '{print $5}'
FILESIZE DA INFORMATION_SCHEMA: È possibile verificare la dimensione del file da information_schema.tables in questo modo:
SELECT (data_length+index_length) tblsize FROM information_schema.tables
WHERE table_schema='mydb' AND table_name='mytable';
Basta sottrarre il valore INFORMATION_SCHEMA dal valore del sistema operativo e dividere la differenza per il valore INFORMATION_SCHEMA.
Da lì deciderai quale percentuale ritiene necessaria per deframmentare quella tabella. Naturalmente, lo deframmenti usando uno dei seguenti comandi:
OPTIMIZE TABLE mydb.mytable;
o
ALTER TABLE mydb.mytable ENGINE=InnoDB;