Suppression et récupération d'espace de la table InnoDB

14

J'ai une table InnoDB de 700 Go dans laquelle je n'écris plus de données (lecture uniquement). Je voudrais supprimer les anciennes données qu'il contient et récupérer cet espace disque (car j'en manque). La partie de suppression est assez facile, car j'ai un index primaire auto-inc afin que je puisse simplement itérer en morceaux en l'utilisant et supprimer les lignes, mais cela ne me ramènera pas l'espace. Je suppose OPTIMIZE TABLEque oui, mais cela pourrait prendre une éternité sur une table de 700 Go, alors y a-t-il une autre option que je néglige?

Édité par RolandoMySQLDBA

En supposant que votre table est mydb.mytable, veuillez exécuter la requête suivante et la publier ici afin que vous puissiez déterminer l'espace disque requis pour la réduction de la table:

SELECT
    FORMAT(dat/POWER(1024,3),2) datsize,
    FORMAT(ndx/POWER(1024,3),2) ndxsize,
    FORMAT((dat+ndx)/POWER(1024,3),2) tblsize
FROM (SELECT data_length dat,index_length ndx
FROM information_schema.tables WHERE
table_schema='mydb' AND table_name='mytable') A;

Nous devons également voir la structure de la table, si cela est autorisé.

Édité par Noam

Voici la sortie de la requête:

datsize ndxsize tblsize
682.51 47.57 730.08

Ceci est la structure de la table ( SHOW CREATE TABLE)

`CREATE TABLE `mybigtable` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `uid` int(11) NOT NULL,  
  `created_at` datetime NOT NULL,  
  `tid` bigint(20) NOT NULL,  
  `text` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, 
  `ft` tinyint(1) NOT NULL,  
  `irtsd` bigint(20) NOT NULL,  
  `irtuid` int(11) NOT NULL,  
  `rc` int(11) NOT NULL,  
  `r` tinyint(1) NOT NULL,  
  `e` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,  `timezone` varchar(5) NOT NULL,  PRIMARY KEY (`id`),  UNIQUE KEY `uid_tid` (`uid`,`tid`)) ENGINE=InnoDB AUTO_INCREMENT=2006963844 DEFAULT CHARSET=utf8`
Noam
la source
Avez-vous un autre volume de disque pour capturer uniquement les données ???
RolandoMySQLDBA
@RolandoMySQLDBA J'ai un disque dur externe que je peux monter. Cela compte-t-il?
Noam
@RolandoMySQLDBA mais aimerait bien sûr une option pour supprimer de l'espace sans avoir besoin d'avoir encore 700 Go
Noam
@RolandoMySQLDBA la taille de disque supplémentaire cause-t-elle des problèmes de performances?
Aris
@Aris, cela peut dépendre du disque et de son temps de recherche. De nos jours, la plupart des disques fonctionnent mieux maintenant, mais à quoi bon gaspiller les cycles (même aller très vite) si vous avez de grandes poches d'espace disque clairsemées dans votre table ???. Cela est particulièrement vrai pour InnoDB qui est normalement fixé à 16K blocs. Avec la fragmentation interne des blocs 16K, vous pouvez vouloir défragmenter la table en utilisant ALTER TABLE ... ENGINE=InnoDB;(si vous avez la place pour le faire). La plupart sont simplement satisfaits de leurs SSD très rapides et ne s'inquiéteraient plus.
RolandoMySQLDBA

Réponses:

21

C'est une bonne question. Vous avez plusieurs solutions mais votre table est assez grande donc aucune ne sera sans douleur :)

Vous avez trois solutions pour "réduire" les tables InnoDB:

1. OPTIMISER LE TABLEAU

Vous pouvez utiliser OPTIMIZE TABLEcomme vous l'avez mentionné, mais vous devez vous soucier de la innodb_file_per_tablevariable:

mysql> show variables like "innodb_file_per_table";
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON    |
+-----------------------+-------+
1 row in set (0.00 sec)

Laissez-moi expliquer:

Le OPTIMIZE TABLEwhith tables InnoDB, verrouille la table, copiez les données dans une nouvelle table propre (c'est pourquoi le résultat est réduit), supprimez la table d'origine et renommez la nouvelle table avec le nom d'origine. C'est pourquoi vous devriez vous soucier d'avoir le double de la volumétrie de votre table disponible sur votre disque (pendant le fonctionnement, vous aurez besoin de 2x700 Go).

Lorsque vous êtes dans le innodb_file_per_table = ON. Toutes les tables ont leur propre fichier de données. Donc, l' OPTIMIZEinstruction créera un nouveau fichier de données (~ 700 Go) lorsque l'opération sera terminée, MySQL supprimera l'original et renommera le nouveau (donc à la fin, les 700 Go - probablement moins car ils seront réduits - de données généré pendant l'opération sera publié)

Lorsque vous êtes dans le innodb_file_per_table = OFF. Toutes les données vont dans un seul fichier de données: ibdata . Ce fichier a une triste particularité, il ne peut pas être réduit. Ainsi, au cours du OPTIMIZEprocessus, votre nouvelle table sera créée (près de 700 Go), mais même après l'opération de suppression et de changement de nom (et la fin de la OPTIMIZEphase), votre ibdata ne libérera pas les ~ 700 Go, donc vous vouliez libérer des données mais vous avez 700 Go en plus, non?

2. ALTER TABLE

Vous pouvez également utiliser une ALTER TABLEinstruction, le ALTER TABLEfonctionnera de la même manière que OPTIMIZE TABLE. Vous pouvez simplement utiliser:

ALTER TABLE myTable EGINE=InnoDB;

3. ALTER TABLE (EN LIGNE)

Le problème de OPTIMIZEet ALTER TABLEqu'il verrouille la table pendant le fonctionnement. Vous pouvez utiliser l'outil Percona: pt-online-schema-change (depuis Percona Toolkit: lien ). pt-online-schema ... construira un mécanisme avec des déclencheurs et une table temporaire que vous permettez à la table d'origine d'être disponible pour la lecture et l'écriture pendant l'opération. J'utilise cet outil en production pour le gros ALTERc'est assez cool.

Notez que vous devriez avoir fait FOREIGN KEYréférence à votre table, FK et les déclencheurs risquent de produire un gâchis. Pour vérifier ces conditions préalables, interrogez:

mysql> SELECT COUNT(*) FROM information_schema.REFERENTIAL_CONSTRAINTS WHERE REFERENCED_TABLE_NAME = "myTable";
+----------+
| COUNT(*) |
+----------+
|        0 |
+----------+
1 row in set (0.04 sec)

Voici comment j'utilise pt-online-schema-change:

pt-online-schema-change --alter "ENGINE=InnoDB" D=myBase,t=myTable --user --ask-pass

Notez que ma note sur innodb_file_per_table est également vraie pour cette solution.

4. mysqldump

La dernière solution consiste à recréer toutes les bases de données à partir d'un vidage. Terriblement long, mais terriblement efficace. Notez que c'est la seule solution pour "réduire" le fichier ibdata.

Max.

Maxime Fouilleul
la source
Également dans l'option de table en ligne de l'outil percona, j'ai besoin de 700 Go d'espace disque libre?
Noam
Oui, pt-online utilise juste un peu de mécanisme pour faire l'ALTER en ligne mais il fait quand même un ALTER.
Maxime Fouilleul
@MaximeFouilleul la taille du disque supplémentaire cause-t-elle des problèmes de performances?
Aris
1

Si vous manquez de taille de disque, je vous suggère de faire comme Max suggéré avec pt-online-schema-change (ONLINE). J'ai été dans la même situation avec une table beaucoup plus petite (200 Go) et j'ai choisi de faire de la compression en même temps. Quelque chose dans le sens de cela devrait fonctionner:

pt-online-schema-change --alter="ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4" D=myBase,t=myTable --user --ask-pass

Cela ne fonctionnera que si vous êtes au format de fichier barracuda et au format COMPACT de la table. Vous devez également activer innodb_file_per_table. Cela peut faire des merveilles sur la taille de votre tableau, surtout s'il y a beaucoup de texte et si vous utilisez des KEY_BLOCK_SIZE plus petits tels que 8K ou même 4K (la valeur par défaut est 16K). Vous pouvez également vérifier combien d'espace vous pouvez gagner à partir de plusieurs benchmarks concernant ce problème sur d'autres blogs, mais la documentation MySQL annonce 25% à 50% (c'était presque 90% pour moi).

Notez que cela peut également affecter les performances lors de l'exécution de SELECT (à partir de la documentation MySQL):

Ainsi, à tout moment, le pool de mémoire tampon peut contenir à la fois les formes compressées et non compressées de la page, ou uniquement la forme compressée de la page, ou ni l'un ni l'autre.

MySQL doit également décompresser les données lorsqu'il n'est pas dans le pool de tampons. Soyez donc prévenu.

Cela a vraiment bien fonctionné dans mon cas. J'avais un long texte. 200 Go sont devenus 26 Go. Les performances n'ont pas été modifiées.

Pour plus d'informations en profondeur, consultez ces liens:

https://dev.mysql.com/doc/refman/5.5/en/innodb-compression-usage.html

https://dev.mysql.com/doc/refman/5.5/en/innodb-compression-internals.html

Chasseur Emeric
la source