2010-09-13 10 views
23

truncate -> dies setzt die gesamte Tabelle zurück, gibt es eine Möglichkeit via truncate bestimmte Datensätze/Prüfbedingungen zurückzusetzen.Truncate mit Bedingung

Zum Beispiel: Ich möchte alle Daten zurücksetzen und die letzten 30 Tage in der Tabelle behalten.

Danke.

Antwort

38

Nein, TRUNCATE ist alles oder nichts. Sie können eine DELETE FROM <table> WHERE <conditions> tun, aber dies verliert die Geschwindigkeit Vorteile von TRUNCATE.

+0

Dank zu halten, dass die Bedingung unter der Annahme, wie verhindere ich letzte 10 Tage Daten und Löschen Sie den Rest (zum Beispiel die Tabelle hat 10 Millionen Datensätze), in einer optimierten Weise. – Sharpeye500

+1

Die Geschwindigkeit von TRUNCATE ist, weil es nicht in die Protokolle schreibt –

21

Die kurze Antwort ist keine: MySQL tut nicht können Sie eine WHERE Klausel in die TRUNCATE Anweisung hinzuzufügen. Hier ist MySQL's documentation über die TRUNCATE Aussage.

Aber die gute Nachricht ist, dass Sie diese Einschränkung (etwas) umgehen können.

Einfach, sicher, sauber, aber langsam Lösung DELETE

Zunächst einmal verwenden, wenn die Tabelle klein genug ist, einfach die DELETE Anweisung (es erwähnt werden mußte):

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

Die LOCK und UNLOCK Aussagen sind nicht obligatorisch, aber sie werden Dinge beschleunigen und mögliche Deadlocks vermeiden.

Leider wird dies sehr langsam sein, wenn Ihr Tisch groß ist ... und da Sie die Verwendung der TRUNCATE-Anweisung in Betracht ziehen, nehme ich an, es liegt daran, dass Ihre Tabelle groß ist.

hier ist also ein Weg, um Ihr Problem mit der TRUNCATE Anweisung zu lösen:

Einfach, schnell, aber unsichere Lösung mit 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; 

Leider ist diese Lösung ein bisschen unsicher, wenn andere Prozesse fügen gleichzeitig Datensätze in die Tabelle ein:

  • beliebig re Das zwischen den Schritten 1 und 2 eingefügte Kabel geht verloren
  • Die TRUNCATE Anweisung setzt den Zähler AUTO-INCREMENT auf Null zurück. Jeder Datensatz, der zwischen den Schritten 2 und 3 eingefügt wird, hat eine ID, die niedriger als die älteren IDs ist und die sogar mit den in Schritt 4 eingefügten IDs kollidieren kann (beachten Sie, dass der Zähler AUTO-INCREMENT nach Schritt 4 wieder seinen korrekten Wert hat).

Leider ist es nicht möglich, die Tabelle zu sperren und abzuschneiden. Aber wir können (irgendwie) um arbeiten, dass Begrenzung unter Verwendung RENAME.

Halb einfach, schnell, sicher, aber laut Lösung 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; 

Dies sollte absolut sicher und sehr schnell mit sein. Das einzige Problem ist, dass andere Prozesse die Tabelle my_table für ein paar Sekunden verschwinden sehen. Dies kann dazu führen, dass Fehler überall in den Protokollen angezeigt werden. Es ist also eine sichere Lösung, aber es ist "laut".

Haftungsausschluss: Ich bin kein MySQL-Experte, also könnten diese Lösungen wirklich beschissen sein. Die einzige Garantie, die ich anbieten kann, ist, dass sie für mich gut funktionieren. Wenn ein Experte diese Lösungen kommentieren kann, wäre ich dankbar.

+0

Große Antwort und nette Art der Arbeit mit den Einschränkungen. Vielen Dank. –

0

Sie können die Tabelle einfach mit einer Abfrageklausel unter Verwendung der Datenpumpe exportieren und sie mit der Klausel table_exists_action = replace zurück importieren. Es wird fallen und Ihren Tisch neu erstellen und sehr wenig Zeit benötigen. Bitte lesen Sie es vor der Implementierung.

0

Als Antwort auf Ihre Frage: "Ich möchte alle Daten zurücksetzen und die letzten 30 Tage in der Tabelle behalten."

können Sie ein Ereignis erstellen. Prüfen https://dev.mysql.com/doc/refman/5.7/en/event-scheduler.html

Zum Beispiel:

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

werde eine tägliche Bereinigung in der Tabelle ausführen, die letzten 30 Tage Daten verfügbar