web-dev-qa-db-fra.com

mysql - La suppression de lignes d'InnoDB est très lente

J'ai une base de données mysql avec env. 1 TB de données. La table fuelinjection_stroke a apprx. 1.000.000.000 de lignes. DBID est la clé primaire qui est automatiquement incrémentée d'une unité à chaque insertion.

J'essaie de supprimer les 1.000.000 premières lignes en utilisant une déclaration très simple:

Delete from fuelinjection_stroke where DBID < 1000000;

Cette requête prend très longtemps (> 24h) sur mon serveur Xcore dédié 8core (mémoire 32 Go, SAS Stockage).

Une idée si le processus peut être accéléré?

12
user1938509

Je crois que ta table devient verrouillée. J'ai rencontré le même problème et découvert que la suppression de 10 000 disques peut être supprimée assez rapidement. Donc, vous voudrez peut-être écrire un script/programme simple qui supprimera des enregistrements par morceaux.

   DELETE FROM fuelinjection_stroke WHERE DBID < 1000000 LIMIT 10000;

Et continue à l'exécuter jusqu'à ce qu'il supprime tout

19
Uriil

Votre espace est-il privé? Le temps d'arrêt est-il impossible?

Sinon, vous pourriez tenir dans une nouvelle longueur de colonne INT 1 et lui attribuer la valeur 1 pour "actif" (ou quelle que soit votre terminologie) et 0 pour "inactif". En fait, vous pouvez utiliser 0 à 9 comme 10 états différents si nécessaire.

L'ajout de cette nouvelle colonne prendra beaucoup de temps, mais une fois terminé, vos mises à jour devraient être extrêmement rapides tant que vous le ferez à partir de PRIMARY (comme vous le faites avec votre DELETE) et que vous n'indexez pas cette nouvelle colonne.

La raison pour laquelle InnoDB met si longtemps à SUPPRIMER sur une table aussi volumineuse que la vôtre est à cause de l'index de cluster. Il ordonne physiquement votre table en fonction de votre PRIMARY (ou du premier UNIQUE trouvé ... ou de ce que l'on ressent s'il ne trouve pas PRIMARY ou UNIQUE), donc lorsque vous tirez une rangée, il réorganise physiquement TOUTE votre table le disque pour la vitesse et la défragmentation. Donc, ce n'est pas le DELETE qui prend si longtemps. C'est la réorganisation physique une fois que cette ligne a été supprimée.

Lorsque vous créez une nouvelle colonne INT avec une valeur par défaut, l'espace est rempli. Ainsi, lorsque vous la mettez à jour, aucune réorganisation physique n'est nécessaire sur votre immense table.

Je ne sais pas exactement quel est votre schéma, mais utiliser une colonne pour l'état d'une ligne est beaucoup plus rapide que DELETEing; Cependant, cela prendra plus d'espace.

Essayez de régler les valeurs:

innodb_flush_log_at_trx_commit=2
innodb_flush_method=O_DIRECT (for non-windows machine)
innodb_buffer_pool_size=25GB (currently it is close to 21GB)
innodb_doublewrite=0
innodb_support_xa=0
innodb_thread_concurrency=0...1000 (try different values, beginning with 200)

Références:

MySQL docs pour la description de différentes variables.

Paramétrage du serveur MySQL

Les bases de l'optimisation des performances MySQL

http://bugs.mysql.com/bug.php?id=28382

5
jmail

Quels index avez-vous?

Je pense que votre problème est que la suppression reconstruit l'index à chaque itération.

Je supprimerais les index le cas échéant, supprimerais puis rajouterais les index. Ce sera beaucoup plus rapide, je pense.

3
i-CONICA

J'avais le même problème et ma table contient plusieurs index que je ne voulais pas avoir à supprimer et à recréer. Alors j'ai fait ce qui suit:

create table keepers
select * from origTable where {clause to retrieve rows to preserve};
truncate table origTable;
insert into origTable null,keepers.col2,...keepers.col(last) from keepers;
drop table keepers;

Environ 2,2 millions de lignes ont été traitées en environ 3 minutes.

1
user5883982

Votre base de données recherche peut-être des enregistrements devant être modifiés dans une clé étrangère (cascades, suppression).

Mais la réponse d’I-Conica est un bon point (+1). Le processus de suppression d'un seul enregistrement et de mise à jour d'un grand nombre d'indexes effectuée 100 000 fois est inefficace. Il suffit de supprimer l'index, de supprimer tous les enregistrements et de le créer à nouveau. 

Et bien sûr, vérifiez s’il existe un quelconque verrou dans la base de données. Un utilisateur ou une application peut verrouiller un enregistrement ou une table et votre requête attendra que l'utilisateur libère la ressource ou que le délai imparti soit dépassé. Une façon de vérifier si votre base de données fonctionne vraiment ou est en attente consiste à lancer la requête à partir d'une connexion qui définit le paramètre --innodb_lock_wait_timeout sur quelques secondes. Si cela échoue au moins, vous savez que la requête est correcte et que vous devez trouver et libérer ce verrou. Select * from XXX est un exemple de verrou utilisé pour les transactions de mise à jour et non validées. 

0
borjab

Pour des tables aussi longues, je préférerais utiliser MYISAM, en particulier si peu de transactions sont nécessaires.

0
user6850438