J'ai résolu ce problème dans StackOverflow en octobre 2010 .
Gardez à l'esprit le fichier le plus occupé de l'infrastructure InnoDB: / var / lib / mysql / ibdata1
Ce fichier contient normalement quatre types d'informations
- Données de table
- Index de table
- Données MVCC (Multiversioning Concurrency Control)
- Métadonnées de table (liste des ID d'espace disque logique)
L'exécution OPTIMIZE TABLE
sur une table InnoDB stockée dans ibdata1 signifie deux choses:
- Rend les données et les index de la table contigus dans ibdata1, donc plus rapides d'accès
- Il fait croître ibdata1 car les pages de données et d'index contiguës sont ajoutées à ibdata1
Bien que vous puissiez séparer les données de table et les index de table d'ibdata1 et les gérer indépendamment en utilisant innodb_file_per_table , le grand espace béant de ibdata1 ne disparaîtra tout simplement pas et ne pourra pas être récupéré. Vous devez en faire plus.
Pour réduire une fois pour toutes ibdata1, vous devez procéder comme suit:
1) MySQLDump toutes les bases de données dans un fichier texte SQL (appelez-le /root/SQLData.sql)
2) Supprimez toutes les bases de données (sauf le schéma mysql)
3) Arrêtez mysql
4) Ajoutez les lignes suivantes à /etc/my.cnf
[mysqld]
innodb_file_per_table
innodb_flush_method=O_DIRECT
innodb_log_file_size=1G
innodb_buffer_pool_size=4G
Sidenote: Quel que soit votre ensemble pour innodb_buffer_pool_size, assurez-vous que innodb_log_file_size représente 25% de innodb_buffer_pool_size.
5) Supprimez ibdata1, ib_logfile0 et ib_logfile1
À ce stade, il ne devrait y avoir que le schéma mysql dans / var / lib / mysql
6) Redémarrez mysql
Cela recréera ibdata1 à 10 ou 18 Mo (selon la version de MySQL), ib_logfile0 et ib_logfile1 à 1G chacun
7) Rechargez /root/SQLData.sql dans mysql
ibdata1 augmentera mais ne contiendra que des métadonnées de table. En fait, il croîtra très lentement au fil des ans. La seule façon dont la croissance d'ibdata1 est rapide est si vous avez un ou plusieurs des éléments suivants:
- Beaucoup de DDL (
CREATE TABLE
, DROP TABLE
, ALTER TABLE
)
- Beaucoup de transactions
- Beaucoup de changements à valider par transaction
Chaque table InnoDB existera en dehors d'ibdata1
Supposons que vous ayez une table InnoDB nommée mydb.mytable. Si vous allez dans / var / lib / mysql / mydb, vous verrez deux fichiers représentant la table
- mytable.frm (en-tête du moteur de stockage)
- mytable.ibd (Accueil des données de table et des index de table pour mydb.mytable)
ibdata1 ne contiendra plus de données et d'index InnoDB.
Avec l'option innodb_file_per_table dans /etc/my.cnf, vous pouvez exécuter OPTIMIZE TABLE mydb.mytable;
et le fichier /var/lib/mysql/mydb/mytable.ibd se réduira réellement.
Je l'ai fait plusieurs fois dans ma carrière en tant que DBA MySQL
En fait, la première fois que j'ai fait cela, j'ai réduit un fichier ibdata1 de 50 Go en 500 Mo.
Essaie. Si vous avez d'autres questions à ce sujet, écrivez-moi. Croyez-moi. Cela fonctionnera à court terme et à long terme !!!
MISE À JOUR 2012-04-19 09:23 EDT
Après avoir exécuté les étapes ci-dessus, comment pouvez-vous déterminer quelles tables doivent être défragmentées? Il est possible de le découvrir, mais vous aurez le script.
Voici un exemple: Supposons que vous ayez la table mydb.mytable
. Avec innodb_file_per_table activé, vous avez le fichier /var/lib/mysql/mydb/mytable.ibd
Vous devrez récupérer deux numéros
FICHIER À PARTIR DE L'OS: vous pouvez vérifier la taille du fichier à partir de l'OS
ls -l /var/lib/mysql/mydb/mytable.ibd | awk '{print $5}'
FILESIZE FROM INFORMATION_SCHEMA: Vous pouvez vérifier la taille de fichier à partir de information_schema.tables comme ceci:
SELECT (data_length+index_length) tblsize FROM information_schema.tables
WHERE table_schema='mydb' AND table_name='mytable';
Il suffit de soustraire la valeur INFORMATION_SCHEMA de la valeur du système d'exploitation et de diviser la différence par la valeur INFORMATION_SCHEMA.
De là, vous décidez quel pourcentage juge nécessaire de défragmenter ce tableau. Bien sûr, vous le défragmentez en utilisant l'une des commandes suivantes:
OPTIMIZE TABLE mydb.mytable;
ou
ALTER TABLE mydb.mytable ENGINE=InnoDB;