MySQL InnoDB ne libère pas d'espace disque après la suppression des lignes de données de la table

140

J'ai une table MySQL utilisant le moteur de stockage InnoDB; il contient environ 2M lignes de données. Lorsque j'ai supprimé des lignes de données de la table, cela n'a pas libéré l'espace disque alloué. La taille du fichier ibdata1 n'a pas non plus été réduite après l'exécution de la optimize tablecommande.

Existe-t-il un moyen de récupérer de l'espace disque sur MySQL?

Je suis dans une mauvaise situation; cette application s'exécute dans environ 50 emplacements différents et maintenant un problème d'espace disque faible apparaît dans presque tous.

Sumit Deo
la source
après avoir exécuté la commande d'optimisation également, la taille du fichier ibdata1 n'a pas été réduite.
Sumit Deo
4
Je pense que ce commentaire serait mieux édité dans votre réponse, puis supprimé
Ben Millwood
duplication possible de stackoverflow.com/q/11751792/82114 (mais celui-ci était ici en premier)
FlipMcF
1
"La taille du fichier ibdata1 n'a pas non plus été réduite après l'exécution de la commande d'optimisation de la table" c'est parce que votre innodb_file_per_tableest désactivé. La bonne nouvelle est que cette option est onpar défaut dans les versions récentes de MySQL.
Accountant م
J'exécute "optimiser la table xxxx" et j'ai reçu le message "La table ne prend pas en charge l'optimisation, en faisant recréer + analyser à la place." Après avoir exécuté "du -h / var / lib / mysql" sur un shell, je pouvais voir que la base de données avait rétréci.
user1097111

Réponses:

137

MySQL ne réduit pas la taille d'ibdata1. Déjà. Même si vous utilisez optimize tablepour libérer l'espace utilisé des enregistrements supprimés, il le réutilisera plus tard.

Une alternative consiste à configurer le serveur à utiliser innodb_file_per_table, mais cela nécessitera une sauvegarde, une suppression de la base de données et une restauration. Le côté positif est que le fichier .ibd de la table est réduit après un optimize table.

Léonel Martins
la source
4
MySQL 5.5 docs sur l'état du mode fichier par table InnoDB «Pour profiter des fonctionnalités [InnoDB fichier par table] pour une table existante, vous pouvez activer le paramètre fichier par table et exécuter ALTER TABLE t ENGINE=INNODBsur la table existante. " Cela implique que vous pouvez activer cette fonctionnalité, "convertir" les tables existantes pour utiliser un fichier InnoDB séparé avec la commande ALTER TABLE, puis OPTIMISER la table pour réduire sa taille. Cependant, une fois que vous avez terminé, vous devrez trouver comment supprimer le (énorme) fichier source InnoDB ...
Josh
9
Je suppose que cela répond techniquement à la question, mais je m'attendrais à ce que la majorité des personnes qui recherchent ce sujet recherchent le processus réel pour réduire / récupérer l'espace, ce que cette réponse ne fournit pas.
Manachi
@Manachi Le processus est "configurer le serveur pour utiliser innodb_file_per_table", "sauvegarder" le serveur, "supprimer la (les) base (s)", arrêter le mysql, supprimer .ibd, démarrer le serveur et restaurer la ou les bases de données. Avec MySQL 5.5+, vous pouvez utiliser ce que Josh a dit, et après avoir changé toutes les tables, arrêtez le serveur, supprimez l'énorme .ibd et redémarrez-le.
Leonel Martins
39

J'ai juste eu le même problème moi-même.

Ce qui se passe, c'est que même si vous supprimez la base de données, innodb ne libère toujours pas d'espace disque. J'ai dû exporter, arrêter mysql, supprimer les fichiers manuellement, démarrer mysql, créer une base de données et des utilisateurs, puis importer. Dieu merci, je n'avais que 200 Mo de lignes, mais cela a épargné 250 Go de fichier innodb.

Échouer par conception.

gilm
la source
10
ouais, c'est définitivement un échec.
trusktr
1
MySql 5.5 a le même problème: j'ai exécuté "optimiser table" pour réduire l'utilisation du disque d'une table de 28 Go. L'opération a probablement essayé de créer un clone optimisé de l'original, ce qui a utilisé tout l'espace sur la partition. Maintenant, "optimiser la table" a échoué et il ne me reste plus d'espace sur la partition même après avoir laissé tomber la totalité de la base de données ... très décevant.
basilikode
1
Et 4+ ans plus tard, j'ai rencontré le même problème avec MySQL. MS SQL est similaire: dba.stackexchange.com/questions/47310/…
Csaba Toth
24

Si vous n'utilisez pas innodb_file_per_table , la récupération de l'espace disque est possible, mais assez fastidieuse, et nécessite un temps d'arrêt important.

Le Comment est assez détaillé - mais j'ai collé la partie pertinente ci-dessous.

Assurez-vous de conserver également une copie de votre schéma dans votre vidage.

Actuellement, vous ne pouvez pas supprimer un fichier de données de l'espace de table système. Pour réduire la taille de l'espace de table système, utilisez cette procédure:

Utilisez mysqldump pour vider toutes vos tables InnoDB.

Arrêtez le serveur.

Supprimez tous les fichiers d'espace de table existants, y compris les fichiers ibdata et ib_log. Si vous souhaitez conserver une copie de sauvegarde des informations, copiez tous les fichiers ib * vers un autre emplacement avant de supprimer les fichiers de votre installation MySQL.

Supprimez tous les fichiers .frm des tables InnoDB.

Configurez un nouvel espace de table.

Redémarrez le serveur.

Importez les fichiers de vidage.

FlipMcF
la source
1
Merci d'avoir inclus les étapes - afaict le lien `` comment faire '' ne contient plus ces informations
aland
3

Dix ans plus tard, j'ai eu le même problème. Je l'ai résolu de la manière suivante:

  • J'ai optimisé toutes les bases de données restées.
  • J'ai redémarré mon ordinateur et MySQL sur les services (Windows + r -> services.msc)

C'est tout :)

Matheus Douglas
la source
1

Une autre façon de résoudre le problème de la récupération d'espace est de créer plusieurs partitions dans la table - Partitions basées sur une plage, basées sur des valeurs et de simplement supprimer / tronquer la partition pour récupérer l'espace, ce qui libérera l'espace utilisé par toutes les données stockées dans la partition particulière.

Il y aura quelques changements nécessaires dans le schéma de la table lorsque vous introduisez le partitionnement de votre table comme - Clés uniques, index pour inclure la colonne de partition, etc.

Anand Immannavar
la source
0

Il y a un an, j'ai également rencontré le même problème sur la version mysql5.7 et ibdata1 occupait 150 Go. alors j'ai ajouté des tablespaces d'annulation

Prendre la sauvegarde Mysqldump
Arrêter le service mysql
Supprimer toutes les données du répertoire de données
Ajouter ci-dessous annuler le paramètre de tablespace dans my.cnf actuel

 #undo tablespace
  innodb_undo_directory =  /var/lib/mysql/
  innodb_rollback_segments = 128 
  innodb_undo_tablespaces = 3
  innodb_undo_logs = 128  
  innodb_max_undo_log_size=1G
  innodb_undo_log_truncate = ON

Démarrer la
sauvegarde de mysqldump du magasin de services mysql

Problème résolu !!

Gajendra
la source
-1

Il existe plusieurs façons de récupérer de l'espace disque après la suppression des données de la table pour le moteur MySQL Inodb

Si vous n'utilisez pas innodb_file_per_table depuis le début, vider toutes les données, supprimer tous les fichiers, recréer la base de données et importer à nouveau les données est le seul moyen (vérifiez les réponses de FlipMcF ci-dessus)

Si vous utilisez innodb_file_per_table, vous pouvez essayer

  1. Si vous pouvez supprimer toutes les données, la commande truncate supprimera les données et récupérera de l'espace disque pour vous.
  2. La commande Alter table supprimera et recréera la table afin qu'elle puisse récupérer de l'espace disque. Par conséquent, après la suppression des données, exécutez alter table qui ne change rien pour libérer le disque dur (c'est-à-dire: la table TBL_A a le jeu de caractères uf8, après la suppression des données, exécutez ALTER TABLE TBL_A charset utf8 -> cette commande ne change rien de votre table mais elle fait recréer votre table et la regagner par mysql espace disque
  3. Créez TBL_B comme TBL_A. Insérez les données sélectionnées que vous souhaitez conserver de TBL_A dans TBL_B. Supprimez TBL_A et renommez TBL_B en TBL_A. Cette méthode est très efficace si TBL_A et les données à supprimer sont volumineuses (la commande de suppression dans MySQL innodb est de très mauvaises performances)
Bùi Đức Khánh
la source