Обрезать с условием - PullRequest
       23

Обрезать с условием

33 голосов
/ 14 сентября 2010

truncate -> сбрасывает всю таблицу, есть ли способ через truncate для сброса определенных записей / проверки условий.

Например: я хочу сбросить все данные и сохранить последние 30 дней в таблице.

Спасибо.

Ответы [ 4 ]

53 голосов
/ 14 сентября 2010

Нет, TRUNCATE - это все или ничего.Вы можете сделать DELETE FROM <table> WHERE <conditions>, но это теряет преимущества скорости TRUNCATE.

27 голосов
/ 07 декабря 2011

Краткий ответ: нет : MySQL не позволяет добавить предложение WHERE в оператор TRUNCATE.Вот документация MySQL об операторе TRUNCATE.

Но хорошей новостью является то, что вы можете (несколько) обойти это ограничение.

Простой, безопасный, чистое, но медленное решение с использованием DELETE

Прежде всего, если таблица достаточно мала, просто используйте оператор DELETE (это должно быть упомянуто):

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

Операторы LOCK и UNLOCK не являются обязательными, но они ускорят работу и позволят избежать потенциальных тупиков.

К сожалению, это будет очень медленно, если ваша таблица велика ... и так каквы рассматриваете возможность использования оператора TRUNCATE, я полагаю, это потому, что ваша таблица велика.

Итак, вот один из способов решения вашей проблемы с помощью оператора TRUNCATE:

Simple, быстрое, но небезопасное решение с использованием 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;

К сожалению, это решение немного небезопасно, если другие процессы одновременно вставляют записи в таблицу:

  • любая запись, вставленная между шагами 1 и2 будет потеряно
  • оператор TRUNCATE сбрасывает счетчик AUTO-INCREMENT в ноль.Поэтому любая запись, вставленная между шагами 2 и 3, будет иметь идентификатор, который будет ниже, чем более старые идентификаторы, и который может даже конфликтовать с идентификаторами, вставленными на шаге 4 (обратите внимание, что счетчик AUTO-INCREMENT вернется к своему надлежащему значению после шага 4).

К сожалению, заблокировать таблицу и обрезать ее невозможно.Но мы можем (как-то) обойти это ограничение , используя RENAME.

Полупростое, быстрое, безопасное, но шумное решение с использованием 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;

Это должно быть абсолютно безопасно и довольно быстро.Единственная проблема заключается в том, что другие процессы увидят, что таблица my_table исчезнет на несколько секунд.Это может привести к появлению ошибок в журналах повсюду.Так что это безопасное решение, но оно «шумное».

Отказ от ответственности : я не эксперт по MySQL, поэтому эти решения могут быть на самом деле дерьмовыми.Единственная гарантия, которую я могу предложить, - это то, что они хорошо работают для меня.Если какой-нибудь эксперт может прокомментировать эти решения, я был бы признателен.

1 голос
/ 23 марта 2017

В ответ на ваш вопрос: «Я хочу сбросить все данные и сохранить последние 30 дней в таблице.»

Вы можете создать событие. Чек https://dev.mysql.com/doc/refman/5.7/en/event-scheduler.html

Например:

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

Запустит ежедневную уборку в вашей таблице, сохраняя данные за последние 30 дней доступными

0 голосов
/ 25 февраля 2015

Вы можете просто экспортировать таблицу с предложением запроса, используя datapump, и импортировать ее обратно с предложением table_exists_action = replace. Его упадет и воссоздаст ваш стол и займет совсем немного времени. Пожалуйста, прочитайте об этом перед внедрением.

...