Усекать с условием

truncate → это сбрасывает всю таблицу, есть ли способ обрезать до reset конкретные записи/условия проверки.

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

Спасибо.

Ответ 1

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

Ответ 2

Короткий ответ нет: 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:

Простое, быстрое, но небезопасное решение с использованием 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 (обратите внимание, что после шага 4 счетчик AUTO-INCREMENT вернется к нему надлежащим образом).

К сожалению, невозможно заблокировать таблицу и усечь ее. Но мы можем (каким-то образом) обойти это ограничение, используя 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, поэтому эти решения могут быть дрянными. Единственная гарантия, которую я могу предложить, это то, что они отлично работают для меня. Если какой-либо эксперт может прокомментировать эти решения, я был бы признателен.

Ответ 3

Как ответ на ваш вопрос: "Я хочу reset все данные и сохраняю последние 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 дней

Ответ 4

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