Comment réduire / purger le fichier ibdata1 dans MySQL


561

J'utilise MySQL dans localhost comme un "outil de requête" pour effectuer des statistiques dans R, c'est-à-dire que chaque fois que j'exécute un script R, je crée une nouvelle base de données (A), crée une nouvelle table (B), importe les données dans B , soumettre une requête pour obtenir ce dont j'ai besoin, puis je laisse tomber B et je laisse tomber A.

Cela fonctionne bien pour moi, mais je me rends compte que la taille du fichier ibdata augmente rapidement, je n'ai rien stocké dans MySQL, mais le fichier ibdata1 dépassait déjà 100 Mo.

J'utilise plus ou moins le paramètre MySQL par défaut pour la configuration, est-il possible de réduire / purger automatiquement le fichier ibdata1 après une période de temps fixe?


Réponses:


778

Cela ibdata1ne rétrécit pas est une fonctionnalité particulièrement ennuyeuse de MySQL. Le ibdata1fichier ne peut en fait être réduit que si vous supprimez toutes les bases de données, supprimez les fichiers et rechargez un vidage.

Mais vous pouvez configurer MySQL pour que chaque table, y compris ses index, soit stockée dans un fichier distinct. De cette façon ibdata1, ne grandira pas autant. Selon le commentaire de Bill Karwin, cela est activé par défaut à partir de la version 5.6.6 de MySQL.

Il y a quelque temps, je l'ai fait. Cependant, pour configurer votre serveur pour utiliser des fichiers distincts pour chaque table, vous devez modifier my.cnfafin d'activer ceci:

[mysqld]
innodb_file_per_table=1

http://dev.mysql.com/doc/refman/5.5/en/innodb-multiple-tablespaces.html

Comme vous voulez récupérer de l'espace, ibdata1vous devez supprimer le fichier:

  1. Faire une mysqldumpde toutes les bases de données, procédures, déclencheurs, etc., à l'exception des bases de données mysqletperformance_schema
  2. Supprimer toutes les bases de données à l'exception des 2 bases de données ci-dessus
  3. Arrêtez mysql
  4. Supprimer ibdata1et ib_logfichiers
  5. Démarrez mysql
  6. Restaurer à partir du vidage

Lorsque vous démarrez MySQL à l'étape 5, les fichiers ibdata1et ib_logseront recréés.

Vous êtes maintenant prêt à partir. Lorsque vous créez une nouvelle base de données pour analyse, les tables seront situées dans des ibd*fichiers séparés , pas dans ibdata1. Comme vous déposez généralement la base de données peu de temps après, les ibd*fichiers seront supprimés.

http://dev.mysql.com/doc/refman/5.1/en/drop-database.html

Vous l'avez probablement vu:
http://bugs.mysql.com/bug.php?id=1341

En utilisant la commande ALTER TABLE <tablename> ENGINE=innodbou OPTIMIZE TABLE <tablename>on peut extraire les données et les pages d'index d'ibdata1 pour séparer les fichiers. Cependant, ibdata1 ne rétrécira que si vous effectuez les étapes ci-dessus.

En ce information_schemaqui concerne le , ce n'est pas nécessaire ni possible de laisser tomber. Il s'agit en fait d'un tas de vues en lecture seule, pas de tableaux. Et aucun fichier ne leur est associé, pas même un répertoire de base de données. Le informations_schemautilise le moteur db de mémoire et est supprimé et régénéré lors de l'arrêt / redémarrage de mysqld. Voir https://dev.mysql.com/doc/refman/5.7/en/information-schema.html .


16
@JordanMagnuson Ne vous embêtez pas à abandonner information_schema. Il s'agit en fait d'un tas de vues en lecture seule, pas de tableaux. Et aucun fichier ne leur est associé. Il n'y a même pas de répertoire pour la base de données. L'information_schema utilise le moteur db de la mémoire et est abandonné et régénéré lors de l'arrêt / redémarrage de mysqld. Voir dev.mysql.com/doc/refman/5.5/en/information-schema.html . Concernant performance_schema, je ne l'ai pas utilisé moi-même.
John P

4
Je ne sais pas si c'est une chose récente, mais une fois que l'option innodb_file_per_table est activée, vous pouvez simplement exécuter "ALTER TABLE <tablename> ENGINE = InnoDB" (même si c'est déjà InnoDB) et il déplacera la table dans son fichier individuel . Pas besoin de supprimer des bases de données et autres.
CR.

3
+1 FWIW, MySQL 5.6 est activé innodb_file_per_tablepar défaut.
Bill Karwin

3
Oui, ibdata1 devrait être présent avec les autres fichiers. Le fichier ibdata1 contiendra toujours des métadonnées sur les tables, le journal d'annulation et les tampons.
John P

1
J'ai manqué d'espace sur mon serveur à cause du fichier ibdata1, donc je ne peux même pas vider les bases de données. Serait-ce la même chose que de simplement déplacer les fichiers dans / var / lib / mysql (sauf "mysql", "ibdata1", "ib_logfile0" et "ib_logfile1"), puis de suivre les étapes? Voir stackoverflow.com/questions/2482491/…
Sophivorus

47

Ajoutant à la réponse de John P ,

Pour un système Linux, les étapes 1 à 6 peuvent être accomplies avec ces commandes:

  1. mysqldump -u [username] -p[root_password] [database_name] > dumpfilename.sql
  2. DROP DATABASE [database_name];
  3. sudo /etc/init.d/mysqld stop
  4. sudo rm /var/lib/mysql/ibdata1
    sudo rm /var/lib/mysql/ib_logfile (et supprimez tout autre ib_logfile qui pourrait être nommé ib_logfile0, ib_logfile1etc ...)
  5. sudo /etc/init.d/mysqld start
  6. create database [database_name];
  7. mysql -u [username]-p[root_password] [database_name] < dumpfilename.sql

Attention: ces instructions vous feront perdre d'autres bases de données si vous avez d'autres bases de données sur cette instance mysql. Assurez-vous que les étapes 1, 2 et 6, 7 sont modifiées pour couvrir toutes les bases de données que vous souhaitez conserver.


6
Vous devez répéter 1,2 et 6 pour chaque base de données contenant des tables InnoDB.
Marquis de Lorne

4
Vous avez besoin de quelques étapes supplémentaires entre # 5 et # 6. Vous devez recréer la base de données et réaffecter les autorisations. Donc, à partir de l'invite de commande client mysql create database database_name;, puisgrant all privileges on database_name.* to 'username'@'localhost' identified by 'password';
Fred

1
@fred Je n'avais pas besoin d'accorder de privilèges lors de cette opération. Peut-être parce que j'ai recréé la base de données avec le même nom?
crmpicco

2
Pour taper le mot de passe à l' Password:invite (ce qui est une pratique plus sûre), il suffit de le mettre -psans mot de passe réel.
ADTC

Les déclencheurs, les événements et les routines / fonctions ne sont pas vidés sauf si vous demandez à mysqldump de le faire. Ajoutez également les déclencheurs, les événements et les routines si l'une de vos bases de données en contient. En outre, il suffit de vider avec --all-databases pour vider toutes les bases de données à la fois au lieu d'une par une.
Friek

34

Lorsque vous supprimez des tables innodb, MySQL ne libère pas l'espace à l'intérieur du fichier ibdata, c'est pourquoi il continue de croître. Ces fichiers ne diminuent presque jamais.

Comment réduire un fichier ibdata existant:

http://dev.mysql.com/doc/refman/5.5/en/innodb-resize-system-tablespace.html

Vous pouvez créer un script et planifier l'exécution du script après une période de temps fixe, mais pour la configuration décrite ci-dessus, il semble que plusieurs espaces disque logiques soient une solution plus simple.

Si vous utilisez l'option de configuration innodb_file_per_table, vous créez plusieurs espaces de table. Autrement dit, MySQL crée des fichiers séparés pour chaque table au lieu d'un fichier partagé. Ces fichiers séparés sont stockés dans le répertoire de la base de données et ils sont supprimés lorsque vous supprimez cette base de données. Cela devrait supprimer la nécessité de réduire / purger les fichiers ibdata dans votre cas.

Plus d'informations sur plusieurs espaces de table:

http://dev.mysql.com/doc/refman/5.5/en/innodb-multiple-tablespaces.html


premier lien rompu, correspondance la plus proche que j'ai pu trouver: dev.mysql.com/doc/refman/5.5/en/…
BlackICE

14

Si vous utilisez le moteur de stockage InnoDB pour (certaines de) vos tables MySQL, vous avez probablement déjà rencontré un problème avec sa configuration par défaut. Comme vous l'avez peut-être remarqué, dans le répertoire de données de votre MySQL (dans Debian / Ubuntu - / var / lib / mysql) se trouve un fichier appelé 'ibdata1'. Il contient presque toutes les données InnoDB (ce n'est pas un journal de transactions) de l'instance MySQL et pourrait devenir assez volumineux. Par défaut, ce fichier a une taille initiale de 10 Mo et il s'étend automatiquement. Malheureusement, de par leur conception, les fichiers de données InnoDB ne peuvent pas être réduits. C'est pourquoi DELETEs, TRUNCATEs, DROP, etc. ne récupéreront pas l'espace utilisé par le fichier.

Je pense que vous pouvez y trouver de bonnes explications et solutions:

http://vdachev.net/2007/02/22/mysql-reducing-ibdata1/


11

Scripté rapidement la procédure de réponse acceptée dans bash:

#!/usr/bin/env bash
DATABASES="$(mysql -e 'show databases \G' | grep "^Database" | grep -v '^Database: mysql$\|^Database: binlog$\|^Database: performance_schema\|^Database: information_schema' | sed 's/^Database: //g')"
mysqldump --databases $DATABASES -r alldatabases.sql && echo "$DATABASES" | while read -r DB; do
    mysql -e "drop database \`$DB\`"
done && \
    /etc/init.d/mysql stop && \
    find /var/lib/mysql -maxdepth 1 -type f \( -name 'ibdata1' -or -name 'ib_logfile*' \) -delete && \
    /etc/init.d/mysql start && \
    mysql < alldatabases.sql && \
    rm -f alldatabases.sql

Enregistrez sous purge_binlogs.shet exécutez sous root.

A l' exclusion mysql, information_schema, performance_schema(et binlogrépertoire).

Suppose que vous possédez des informations d'identification d'administrateur /root/.my.cnfet que votre base de données réside dans le /var/lib/mysqlrépertoire par défaut .

Vous pouvez également purger les journaux binaires après avoir exécuté ce script pour regagner plus d'espace disque avec:

PURGE BINARY LOGS BEFORE CURRENT_TIMESTAMP;

Je ne sais toujours pas pourquoi, mais aujourd'hui certaines de mes tables InnoDB ont été corrompues au cours d'un processus similaire, donc je ne supprimerais pas alldatabases.sqlavant de vérifier si toutes les tables sont saines. En ce qui concerne certaines améliorations: définir innodb_fast_shutdown=0avant l'arrêt, définir autocommit=0avant d'importer le fichier SQL, exécuter COMMITet définir autocommit=1après l'importation du fichier SQL, utiliser mysqlcheck --all-databasesavant de supprimer la sauvegarde.
Victor

6

Si votre objectif est de surveiller l'espace libre de MySQL et que vous ne pouvez pas empêcher MySQL de réduire votre fichier ibdata, alors obtenez-le via les commandes d'état de la table. Exemple:

MySQL> 5.1.24:

mysqlshow --status myInnodbDatabase myTable | awk '{print $20}'

MySQL <5.1.24:

mysqlshow --status myInnodbDatabase myTable | awk '{print $35}'

Comparez ensuite cette valeur à votre fichier ibdata:

du -b ibdata1

Source: http://dev.mysql.com/doc/refman/5.1/en/show-table-status.html


4

Dans une nouvelle version des recettes de mysql-server ci-dessus écrasera la base de données "mysql". Dans l'ancienne version, cela fonctionne. Dans de nouvelles tables, certains commutent vers le type de table INNODB et, ce faisant, vous les endommagerez. Le moyen le plus simple consiste à:

  • vider toutes vos bases de données
  • désinstaller mysql-server,
  • ajouter est resté my.cnf:
    [mysqld]
    innodb_file_per_table=1
  • tout effacer dans / var / lib / mysql
  • installer mysql-server
  • restaurer les utilisateurs et les bases de données

1

Comme déjà indiqué, vous ne pouvez pas réduire ibdata1 (pour ce faire, vous devez vider et reconstruire), mais il n'y a souvent pas vraiment de besoin.

L'utilisation de l'extension automatique (probablement le paramètre de taille le plus courant) ibdata1 préalloue le stockage, augmentant chaque fois qu'il est presque plein. Cela accélère les écritures car l'espace est déjà alloué.

Lorsque vous supprimez des données, elles ne diminuent pas, mais l'espace à l'intérieur du fichier est marqué comme inutilisé. Maintenant, lorsque vous insérez de nouvelles données, il réutilisera l'espace vide dans le fichier avant de l'agrandir davantage.

Donc, cela ne continuera de croître que si vous avez réellement besoin de ces données. À moins que vous n'ayez réellement besoin d'espace pour une autre application, il n'y a probablement aucune raison de la réduire.


66
Je pense que vous êtes un peu trop dédaigneux de la nécessité de libérer de l'espace.
drewish

2
J'ai une partition Solid State 60Gig. Je manque rapidement d'espace, car je travaille avec des bases de données 4 + gig. Je cherche à déplacer mysql vers une autre partition bientôt, mais cette question et ses réponses m'aideront en attendant
NullVoxPopuli

3
Merci pour cette réponse, c'est très utile. J'ai effacé certaines tables des données héritées ... il est bon de savoir que la taille du disque ne augmentera pas de sitôt.
Brad

1
J'ai un fichier ibdata1 500G - mais presque toutes les données qui y étaient stockées sont maintenant stockées dans des fichiers par base de données. J'ai bien besoin de rétrécir ce gaspillage colossal d'espace!
frankster

2
Un non-sens complet! Un fichier qui continue de gonfler doit être coupé, que vous manquiez d'espace ou non . Je l'appellerais un storage leak.
2017 ADTC
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.