web-dev-qa-db-fra.com

Tronquer avec condition

truncate -> cela réinitialise la table entière, existe-t-il un moyen via truncate de réinitialiser des enregistrements/conditions de contrôle particuliers.

Par exemple, je veux réinitialiser toutes les données et conserver les 30 derniers jours à l'intérieur du tableau.

Merci.

33
Sharpeye500

Non, TRUNCATE est tout ou rien. Vous pouvez faire un DELETE FROM <table> WHERE <conditions> mais ceci perd l'avantage de la rapidité TRUNCATE.

51
ceejayoz

La réponse courte est non: MySQL permet pas vous permet d'ajouter une clause WHERE à l'instruction TRUNCATE. Voici la documentation de MySQL à propos de l'instruction TRUNCATE.

Mais la bonne nouvelle est que vous pouvez (quelque peu) contourner cette limitation.

Solution simple, sûre, propre mais lente utilisant DELETE

Tout d’abord, si la table est suffisamment petite, utilisez simplement l’énoncé DELETE (il faut le mentionner):

1. LOCK TABLE my_table WRITE;
2. DELETE FROM my_table WHERE my_date<DATE_SUB(NOW(), INTERVAL 1 MONTH);
3. UNLOCK TABLES;

Les déclarations LOCK et UNLOCK__ ne sont pas obligatoires, mais elles vont accélérer les choses et éviter les blocages potentiels.

Malheureusement, cela sera très lent si votre table est grande ... et puisque vous envisagez d'utiliser l'instruction TRUNCATE, je suppose que c'est parce que votre table est grande.

Voici donc un moyen de résoudre votre problème en utilisant l'instruction TRUNCATE:

Solution simple, rapide mais dangereuse utilisant TRUNCATE

1. CREATE TABLE my_table_backup AS
      SELECT * FROM my_table WHERE my_date>=DATE_SUB(NOW(), INTERVAL 1 MONTH);
2. TRUNCATE my_table;
3. LOCK TABLE my_table WRITE, my_table_backup WRITE;
4. INSERT INTO my_table SELECT * FROM my_table_backup;
5. UNLOCK TABLES;
6. DROP TABLE my_table_backup;

Malheureusement, cette solution est un peu dangereuse si d'autres processus insèrent des enregistrements dans la table en même temps:

  • tout enregistrement inséré entre les étapes 1 et 2 sera perdu
  • l'instruction TRUNCATE réinitialise le compteur AUTO-INCREMENT à zéro. Ainsi, tout enregistrement inséré entre les étapes 2 et 3 aura un identifiant qui sera inférieur aux identifiants plus anciens et qui pourrait même entrer en conflit avec les identifiants insérés à l'étape 4 (notez que le compteur AUTO-INCREMENT retrouvera sa valeur correcte après l'étape 4).

Malheureusement, il n'est pas possible de verrouiller la table et de la tronquer. Mais nous pouvons (en quelque sorte) contourner cela limitation en utilisant RENAME.

Solution simple, rapide, sûre mais bruyante utilisant TRUNCATE

1. RENAME TABLE my_table TO my_table_work;
2. CREATE TABLE my_table_backup AS
     SELECT * FROM my_table_work WHERE my_date>DATE_SUB(NOW(), INTERVAL 1 MONTH);
3. TRUNCATE my_table_work;
4. LOCK TABLE my_table_work WRITE, my_table_backup WRITE;
5. INSERT INTO my_table_work SELECT * FROM my_table_backup;
6. UNLOCK TABLES;
7. RENAME TABLE my_table_work TO my_table;
8. DROP TABLE my_table_backup;

Cela devrait être complètement sûr et assez rapide. Le seul problème est que d’autres processus verront la table my_table disparaître pendant quelques secondes. Cela pourrait entraîner des erreurs dans les journaux partout. Donc, c'est une solution sûre, mais c'est "bruyant".

_ {Disclaimer} _: Je ne suis pas un expert de MySQL. Ces solutions pourraient donc être vraiment nulles. La seule garantie que je puisse offrir, c'est qu'ils fonctionnent bien pour moi. Si un expert peut commenter ces solutions, je vous en serais reconnaissant.

27
MiniQuark

En réponse à votre question: "Je veux réinitialiser toutes les données et conserver les 30 derniers jours à l'intérieur du tableau."

vous pouvez créer un événement. Vérifiez https://dev.mysql.com/doc/refman/5.7/en/event-scheduler.html

Par exemple:

CREATE EVENT DeleteExpiredLog
ON SCHEDULE EVERY 1 DAY
DO
DELETE FROM log WHERE date < DATE_SUB(NOW(), INTERVAL 30 DAY);

Exécuter un nettoyage quotidien dans votre table, en gardant les données des 30 derniers jours disponibles

1
Felipe Torres

Vous pouvez simplement exporter la table avec une clause query à l'aide de datapump et l'importer à nouveau avec table_exists_action = replace. Son va déposer et recréer votre table et prend très peu de temps. S'il vous plaît lire à ce sujet avant de mettre en œuvre.

0
user4603856