Comment supprimer la fragmentation des tables InnoDB?

13

J'ai une base de données ayant un certain nombre de tables.

Je souhaite supprimer certains enregistrements des tables, car le nombre d'enregistrements dépasse 20 000 ou 50 000.

Toutes les tables sont InnoDB. Et file_per_tablec'est éteint .

Lorsque je supprimerai les enregistrements d'un certain nombre de tables, il y aura une fragmentation dans les tables.

Existe-t-il un moyen de supprimer la fragmentation.?

Mise à jour le 17 avril

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)

Alors maintenant, ma question est de savoir comment je déciderai que mes tables sont fragmentées ou non.

Abdul Manaf
la source
Documents
1
Et un article InnoDB: s'occuper de la fragmentation du site de blog de Percona.
ypercubeᵀᴹ

Réponses:

14

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 TABLEsur 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;
RolandoMySQLDBA
la source
je ne pense pas que / var / lib / mysql / ibdata1 soit très occupé si vous utilisez l'option recommandée innodb_file_per_table = 1
CrackerJack9
1
@ CrackerJack9 ibdata1 est incroyablement superbusy à cause de ce qu'il contient: 1) Informations sur le tampon d'écriture double, 2) Insérer un tampon pour les index secondaires, 3) Dictionnaire de données, 4) Segments de restauration, 5) Annuler le tablespace. Veuillez aller sur scribd.com/doc/31337494/XtraDB-InnoDB-internals-in-drawing pour une représentation graphique de ces choses. Même avec la suppression des données et des pages d'index pour les tables InnoDB, ibdata1 peut encore croître considérablement dans un environnement transactionnel élevé.
RolandoMySQLDBA
1
@ CrackerJack9 J'ai un article supplémentaire sur l'activité supplémentaire autour d'ibdata1: dba.stackexchange.com/a/23367/877
RolandoMySQLDBA
Je ne m'étais pas rendu compte qu'il était toujours aussi utilisé. Très appréciée!
CrackerJack9
@RolandoMySQLDBA Pouvez-vous sauter sur le tas quand vous en avez le temps?
ypercubeᵀᴹ
5

Si vous supprimez fréquemment des lignes (ou mettez à jour des lignes avec des types de données de longueur variable), vous pouvez vous retrouver avec beaucoup d'espace gaspillé dans vos fichiers de données, semblable à la fragmentation du système de fichiers.

Si vous n'utilisez pas l' innodb_file_per_tableoption, la seule chose que vous pouvez faire à ce sujet est d'exporter et d'importer la base de données, une procédure gourmande en temps et en disque.

Mais si vous utilisez innodb_file_per_table, vous pouvez identifier et récupérer cet espace!

Avant la version 5.1.21, le compteur d'espace libre est disponible dans la colonne table_comment de information_schema.tables. Voici du SQL pour identifier les tables avec au moins 100M (en fait 97,65M) d'espace libre:

SELECT table_schema, table_name, table_comment FROM
information_schema.tables WHERE ENGINE LIKE 'InnoDB' ET table_comment RLIKE 'InnoDB free: ([0-9] {6,}). *';

À partir de la version 5.1.21, cela a été déplacé vers la colonne data_free (un endroit beaucoup plus approprié):

SELECT table_schema, table_name, data_free / 1024/1024 AS data_free_MB FROM information_schema.tables OERE LE MOTEUR COMME 'InnoDB' ET data_free> 100 * 1024 * 1024;

Vous pouvez récupérer l'espace perdu en reconstruisant la table. La meilleure façon de le faire est d'utiliser 'alter table' sans rien changer:

ALTER TABLE `TableName` ENGINE=InnoDB;

C'est ce que fait MySQL en arrière-plan si vous exécutez «optimiser la table» sur une table InnoDB. Il en résultera un verrou en lecture, mais pas un verrou de table complet. Le temps nécessaire dépend entièrement de la quantité de données dans le tableau (mais pas de la taille du fichier de données). Si vous avez une table avec un volume élevé de suppressions ou de mises à jour, vous souhaiterez peut-être l'exécuter tous les mois, voire chaque semaine.

Mahesh Patil
la source
Encore une chose que je ne peux pas comprendre ce que signifie data_free> 100 * 1024 * 1024 ..? Et quand j'ai vu le résultat, je suis incapable de décider que la table est fragmentée ou non .. ?? Y at-il un moyen pour peut dire que le tableau est fragmenté ou non fragmenté.?
Abdul Manaf
jetez un oeil à la partie ma mise à jour.
Abdul Manaf