Comment: nettoyer un moteur de stockage mysql InnoDB?

133

Est-il possible de nettoyer un moteur de stockage mysql innodb pour qu'il ne stocke pas les données des tables supprimées?

Ou dois-je reconstruire une nouvelle base de données à chaque fois?

Champ Bryan
la source
Qu'est-ce qui vous fait penser que MySQL stocke les données des tables supprimées?
Robert Munteanu
1
Si je laisse tomber tout un tas d'énormes tables, mes fichiers de stockage InnoDB ne rétrécissent pas
Bryan Field
2
@RobertMunteanu: voir bugs.mysql.com/bug.php?id=1341
Max

Réponses:

351

Voici une réponse plus complète concernant InnoDB. C'est un processus un peu long, mais cela peut en valoir la peine.

Gardez à l'esprit qu'il /var/lib/mysql/ibdata1s'agit du fichier le plus chargé de l'infrastructure InnoDB. Il contient normalement six types d'informations:

  • Données de table
  • Index de table
  • Données MVCC (Multiversioning Concurrency Control)
    • Segments de restauration
    • Annuler l'espace
  • Métadonnées de table (dictionnaire de données)
  • Double tampon d'écriture (écriture en arrière-plan pour éviter de dépendre de la mise en cache du système d'exploitation)
  • Insérer un tampon (gestion des modifications apportées aux index secondaires non uniques)
  • Voir le Pictorial Representation of ibdata1

Architecture InnoDB

Architecture InnoDB

De nombreuses personnes créent plusieurs ibdatafichiers dans l'espoir d'une meilleure gestion de l'espace disque et de meilleures performances, mais cette croyance est erronée.

Puis-je courir OPTIMIZE TABLE?

Malheureusement, l'exécution OPTIMIZE TABLEsur une table InnoDB stockée dans le fichier d'espace table partagé ibdata1fait deux choses:

  • Rend les données et les index de la table contigus à l'intérieur ibdata1
  • Fait ibdata1grandir car les données contiguës et les pages d'index sont ajoutées àibdata1

Vous pouvez cependant séparer les données de table et les index de table ibdata1et les gérer indépendamment.

Puis-je courir OPTIMIZE TABLEavec innodb_file_per_table?

Supposons que vous deviez ajouter innodb_file_per_tableà /etc/my.cnf (my.ini). Pouvez-vous alors simplement exécuter OPTIMIZE TABLEtoutes les tables InnoDB?

Bonne nouvelle : lorsque vous exécutez OPTIMIZE TABLEavec innodb_file_per_tableactivé, cela produira un .ibdfichier pour cette table. Par exemple, si vous avez une table mydb.mytableavec un datadir de /var/lib/mysql, il produira ce qui suit:

  • /var/lib/mysql/mydb/mytable.frm
  • /var/lib/mysql/mydb/mytable.ibd

Le .ibdcontiendra les pages de données et les pages d'index de cette table. Génial.

Mauvaise nouvelle : Tout ce que vous avez fait est d'extraire les pages de données et les pages d'index mydb.mytablede vivre dans ibdata. L'entrée du dictionnaire de données pour chaque table, y compris mydb.mytable, reste toujours dans le dictionnaire de données (voir la représentation illustrée d'ibdata1 ). VOUS NE POUVEZ PAS SIMPLEMENT SUPPRIMER ibdata1À CE POINT !!! Veuillez noter que cela ibdata1n'a pas du tout diminué.

Nettoyage de l'infrastructure InnoDB

Pour réduire ibdata1une fois pour toutes, vous devez faire ce qui suit:

  1. Dump (par exemple, avec mysqldump) toutes les bases de données dans un .sqlfichier texte ( SQLData.sqlest utilisé ci-dessous)

  2. Supprimez toutes les bases de données (à l'exception de mysqlet information_schema) CAVEAT : Par précaution, veuillez exécuter ce script pour vous assurer que toutes les autorisations utilisateur sont en place:

    mkdir /var/lib/mysql_grants
    cp /var/lib/mysql/mysql/* /var/lib/mysql_grants/.
    chown -R mysql:mysql /var/lib/mysql_grants
  3. Connectez-vous à mysql et exécutez SET GLOBAL innodb_fast_shutdown = 0;(cela supprimera complètement toutes les modifications transactionnelles restantes de ib_logfile0et ib_logfile1)

  4. Arrêter MySQL

  5. Ajoutez les lignes suivantes à /etc/my.cnf(ou my.inisous Windows)

    [mysqld]
    innodb_file_per_table
    innodb_flush_method=O_DIRECT
    innodb_log_file_size=1G
    innodb_buffer_pool_size=4G

    (Note de bas de page: quel que soit votre jeu innodb_buffer_pool_size, assurez-vous que innodb_log_file_size25% de innodb_buffer_pool_size.

    Aussi: innodb_flush_method=O_DIRECTn'est pas disponible sous Windows)

  6. Supprimer ibdata*et ib_logfile*, éventuellement, vous pouvez supprimer tous les dossiers dans /var/lib/mysql, sauf /var/lib/mysql/mysql.

  7. Démarrez MySQL (cela recréera ibdata1[10 Mo par défaut] et ib_logfile0et ib_logfile1à 1G chacun).

  8. Importer SQLData.sql

Maintenant, ibdata1continuera de croître mais ne contiendra que des métadonnées de table car chaque table InnoDB existera en dehors de ibdata1. ibdata1ne contiendra plus les données InnoDB et les index des autres tables.

Par exemple, supposons que vous ayez une table InnoDB nommée mydb.mytable. Si vous regardez dedans /var/lib/mysql/mydb, vous verrez deux fichiers représentant la table:

  • mytable.frm (En-tête du moteur de stockage)
  • mytable.ibd (Données de table et index)

Avec l' innodb_file_per_tableoption dans /etc/my.cnf, vous pouvez exécuter OPTIMIZE TABLE mydb.mytableet le fichier /var/lib/mysql/mydb/mytable.ibdsera en fait réduit.

J'ai fait cela 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 de 50 Go ibdata1 à seulement 500 Mo!

Essaie. Si vous avez d'autres questions à ce sujet, demandez simplement. Croyez-moi; cela fonctionnera aussi bien à court terme qu'à long terme.

CAVEAT

À l'étape 6, si mysql ne peut pas redémarrer en raison de la mysqlsuppression du début du schéma, revenez à l'étape 2. Vous avez fait la copie physique du mysqlschéma. Vous pouvez le restaurer comme suit:

mkdir /var/lib/mysql/mysql
cp /var/lib/mysql_grants/* /var/lib/mysql/mysql
chown -R mysql:mysql /var/lib/mysql/mysql

Revenez à l'étape 6 et continuez

MISE À JOUR 2013-06-04 11:13 EDT

En ce qui concerne la définition de innodb_log_file_size à 25% de innodb_buffer_pool_size à l'étape 5, cette règle générale est plutôt ancienne.

De retour July 03, 2006, Percona avait un bel article sur les raisons pour lesquelles choisir un innodb_log_file_size approprié . Plus tard, Nov 21, 2008Percona a poursuivi avec un autre article sur la façon de calculer la taille appropriée en fonction de la charge de travail maximale en conservant une heure de changements .

J'ai depuis écrit des articles dans le DBA StackExchange sur le calcul de la taille du journal et où j'ai référencé ces deux articles Percona.

Personnellement, j'irais toujours avec la règle des 25% pour une configuration initiale. Ensuite, comme la charge de travail peut être déterminée avec plus de précision au fil du temps en production, vous pouvez redimensionner les journaux pendant un cycle de maintenance en quelques minutes.

RolandoMySQLDBA
la source
9
J'ai également utilisé l'option innodb_file_per_table à bon escient, ayant 200 bases de données avec 200 tables chacune sur un seul serveur, j'ai pu créer un lien symbolique entre les bases de données de différence sur différentes partitions, utilisant donc plus de tampons IO et de broches qui auraient autrement été disponibles :)
Dave Rix
2
@SeanDowney BTW n'oubliez pas de relancer innodb_open_tablessi nécessaire. La valeur par défaut est 300.
RolandoMySQLDBA
2
@ giorgio79 vous devez définir votre insertion en masse sur une valeur plus élevée. C'est un bon point. J'ajouterai l'essentiel de votre question à ma réponse.
RolandoMySQLDBA
3
Dans les systèmes 32 bits, une valeur de 4 Go pour innodb_buffer_pool_size n'est pas autorisée. Mysql démarrera silencieusement avec innodb désactivé et les tables restaurées seront changées en myisam. Utilisez une valeur légèrement plus petite pour le corriger.
David
5
Bon dieu. Je veux juste dire que c'est peut-être l'une des meilleures réponses que j'aie jamais vues sur Tellement bon travail, monsieur. M'a aidé à trouver une solution à mon problème lorsque j'obtenais une ERREUR 2013 (HY000) lors de l'importation d'une base de données de 154g. Merci pour l'excellente réponse!
Josh Brown
4

Le moteur InnoDB ne stocke pas les données supprimées. Lorsque vous insérez et supprimez des lignes, l'espace inutilisé reste alloué dans les fichiers de stockage InnoDB. Au fil du temps, l'espace global ne diminuera pas, mais avec le temps l'espace «supprimé et libéré» sera automatiquement réutilisé par le serveur de base de données.

Vous pouvez affiner et gérer l'espace utilisé par le moteur grâce à une réorganisation manuelle des tables. Pour ce faire, videz les données dans les tables affectées à l'aide de mysqldump, supprimez les tables, redémarrez le service mysql, puis recréez les tables à partir des fichiers de vidage.

bigjeff
la source