web-dev-qa-db-fra.com

Comment supprimer la fragmentation des tables InnoDB?

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

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

Toutes les tables sont InnoDB. Et file_per_table est désactivé.

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.

13
Abdul Manaf

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)

Fonctionnement OPTIMIZE TABLE par rapport à une table InnoDB stockée dans ibdata1 fait 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) Supprimer 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 de développer rapidement ibdata1 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 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

FICHIERS À PARTIR DE L'OS: Vous pouvez vérifier la taille des fichiers à partir de l'OS comme ceci

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;
14
RolandoMySQLDBA

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 le innodb_file_per_table option, 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 OERE LE MOTEUR COMME 'InnoDB' ET table_comment RLIKE 'InnoDB gratuit: ([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 procéder est d’utiliser ‘alter table’ sans rien changer:

ALTER TABLE `TableName` ENGINE=InnoDB;

C'est ce que MySQL fait en arrière-plan si vous exécutez ‘Optimiser 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.

5
Mahesh Patil