web-dev-qa-db-fra.com

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

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 TABLE le fera, mais cela pourrait prendre une éternité sur une table de 700 Go. Y a-t-il une autre option que j'envisage?

É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 le rétrécissement 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

Il s'agit de 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`
18
Noam

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 TABLE comme vous l'avez mentionné, mais vous devriez vous soucier du innodb_file_per_table variable:

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

Laisse-moi expliquer:

Le OPTIMIZE TABLE avec les tables InnoDB, verrouille la table, copie les données dans une nouvelle table propre (c'est pourquoi le résultat est plus petit), supprime la table d'origine et renomme la nouvelle table avec le nom d'origine. C'est pourquoi vous devez vous assurer d'avoir deux fois l'espace de la table d'origine disponible sur votre disque (vous aurez probablement besoin de moins, car la table optimisée sera plus petite, mais il vaut mieux prévenir que guérir).

innodb_file_per_table = ON: Dans ce mode, toutes les tables ont leur propre fichier de données. L'instruction OPTIMIZE créera alors un nouveau fichier de données avec une utilisation optimisée de l'espace. Lorsque l'opération est terminée, MySQL supprimera l'original et le remplacera par la version optimisée (donc à la fin, les 700 Go - probablement moins car ils seront optimisés - des données générées pendant l'opération seront libérés)

innodb_file_per_table = OFF: Dans ce mode, toutes les données sont contenues dans un fichier de données: ibdata . Ce mode présente un gros inconvénient car il ne peut pas être optimisé. Ainsi, pendant le processus OPTIMIZE, 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 phase OPTIMIZE) votre ibdata ne libérera pas les ~ 700 Go, donc vous vouliez libérer des données, au lieu de cela vous avez 700 Go de plus, cool n'est-ce pas?

2. ALTER TABLE

Vous pouvez également utiliser un ALTER TABLE, l'instruction ALTER TABLE fonctionnera de la même manière que OPTIMIZE TABLE. Vous pouvez simplement utiliser:

ALTER TABLE myTable ENGINE=InnoDB;

3. ALTER TABLE (EN LIGNE)

Le problème de OPTIMIZE et ALTER TABLE signifie qu'il verrouille la table pendant le fonctionnement. Vous pouvez utiliser l'outil Percona: pt-online-schema-change (de Percona Toolkit: link ). pt-online-schema ... fournit des mécanismes pour optimiser la table, tout en gardant la table d'origine disponible pour la lecture et l'écriture. J'utilise cet outil en production pour les instructions ALTER sur de grandes tables et c'est plutôt cool.

Notez que tout FOREIGN KEYs référençant votre table peut compliquer les choses, car les verrous peuvent entraîner des verrous sur d'autres tables, etc. Pour vérifier cela, il suffit de demander:

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 valable pour cette solution.

4. mysqldump

La dernière solution consiste à recréer toutes les bases de données à partir d'un vidage. Cela prend une éternité, mais c'est extrêmement efficace. Notez que c'est la seule solution pour optimiser votre fichier ibdata, si innodb_file_per_table est OFF

Max.

25
Maxime Fouilleul

Si vous êtes à court 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 une 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 la sélection 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

1
Emeric Hunter