Come si rimuove la frammentazione dalle tabelle InnoDB?


13

Ho un database con numero di tabelle.

Voglio eliminare alcuni record dalle tabelle dicendo che il numero di record è superiore a 20K o 50K.

Tutte le tabelle sono InnoDB. Ed file_per_tableè spento .

Quando eliminerò i record da un numero di tabelle ci sarà frammentazione nelle tabelle.

C'è un modo per rimuovere la frammentazione.

Aggiornamento il 17 aprile

mysql> select TABLE_NAME, TABLE_SCHEMA, Data_free from information_schema.TABLES where TABLE_SCHEMA NOT IN ('information_schema', 'mysql') and Data_Free >0;
+-----------------+--------------+-----------+
| TABLE_NAME      | TABLE_SCHEMA | Data_free |
+-----------------+--------------+-----------+
| City            | world_innodb |   5242880 |
| City_Copy       | world_innodb |   5242880 |
| Country         | world_innodb |   5242880 |
| CountryLanguage | world_innodb |   5242880 |
| a               | world_innodb |   5242880 |
| t1              | world_innodb |   5242880 |
| t2              | world_innodb |   5242880 |
+-----------------+--------------+-----------+
7 rows in set (0.00 sec)

Quindi ora la mia domanda è che come deciderò che i miei tavoli sono frammentati o meno.



1
E un articolo InnoDB: prenditi cura della frammentazione dal sito del blog di Percona.
ypercubeᵀᴹ

Risposte:


14

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 TABLEsu 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;

non credo che / var / lib / mysql / ibdata1 sia molto occupato se si utilizza l'opzione innodb_file_per_table = 1 consigliata
CrackerJack9

1
@ CrackerJack9 ibdata1 è incredibilmente superbusy a causa di ciò che lo riguarda: 1) Doppia informazione sul buffer di scrittura, 2) Inserisci buffer per indici secondari, 3) Dizionario dei dati, 4) Segmenti di rollback, 5) Annulla tablespace. Si prega di goto scribd.com/doc/31337494/XtraDB-InnoDB-internals-in-drawing per una rappresentazione pittorica di queste cose. Anche con la rimozione di pagine di dati e indici per le tabelle InnoDB, ibdata1 può comunque crescere in modo significativo in un ambiente transazionale elevato.
RolandoMySQLDBA

1
@ CrackerJack9 Ho un post aggiuntivo che discute l'attività aggiuntiva attorno a ibdata1: dba.stackexchange.com/a/23367/877
RolandoMySQLDBA

Non mi ero reso conto che fosse ancora usato così pesantemente. Molto apprezzato!
CrackerJack9,

@RolandoMySQLDBA Puoi fare un salto all'Heap quando hai tempo?
ypercubeᵀᴹ

5

Se elimini frequentemente le righe (o aggiorni le righe con tipi di dati a lunghezza variabile), puoi finire con molto spazio sprecato nei tuoi file di dati, simile alla frammentazione del filesystem.

Se non si utilizza l' innodb_file_per_tableopzione, l'unica cosa che si può fare al riguardo è esportare e importare il database, una procedura che richiede molto tempo e disco.

Ma se stai usando innodb_file_per_table, puoi identificare e recuperare questo spazio!

Prima della 5.1.21, il contatore dello spazio libero era disponibile dalla colonna table_comment di information_schema.tables. Ecco alcuni SQL per identificare le tabelle con almeno 100 M (in realtà 97.65 M) di spazio libero:

SELEZIONA table_schema, table_name, table_comment DA
information_schema.tables DOVE MOTORE COME 'InnoDB' E table_comment RLIKE 'InnoDB gratuito: ([0-9] {6,}). *';

A partire dalla 5.1.21, questo è stato spostato nella colonna data_free (un posto molto più appropriato):

SELEZIONA table_schema, table_name, data_free / 1024/1024 AS data_free_MB DA information_schema.tables DOVE MOTORE COME 'InnoDB' E data_free> 100 * 1024 * 1024;

Puoi recuperare lo spazio perso ricostruendo la tabella. Il modo migliore per farlo è usare 'alter table' senza cambiare nulla:

ALTER TABLE `TableName` ENGINE=InnoDB;

Questo è ciò che MySQL fa dietro le quinte se si esegue "ottimizza tabella" su una tabella InnoDB. Si tradurrà in un blocco di lettura, ma non in un blocco completo della tabella. Il tempo necessario dipende completamente dalla quantità di dati nella tabella (ma non dalle dimensioni del file di dati). Se disponi di una tabella con un volume elevato di eliminazioni o aggiornamenti, potresti voler eseguire questo mensile o anche settimanalmente.


Un'altra cosa che non riesco a capire cosa significa data_free> 100 * 1024 * 1024 ..? E quando ho visto il risultato non sono in grado di decidere che la tabella è frammentata o no .. ?? C'è un modo in cui posso dire che la tabella è frammentata o non frammentata.
Abdul Manaf,

dai un'occhiata alla mia parte di aggiornamento.
Abdul Manaf,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.