2010-09-13 3 views
23

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

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

Спасибо.

ответ

38

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

+0

Спасибо, предполагая, что условие, как я держу последние 10 дней данные и удалить остальные (например, таблица имеет 10 миллионов записей), оптимизированным образом. – Sharpeye500

+1

Скорость от TRUNCATE заключается в том, что она не записывает в журналы –

21

Короткий ответ нет: MySQL делает не позволяет добавить пункт WHERE в TRUNCATE заявлении. Вот MySQL's documentation о заявлении 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.

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

+0

Отличный ответ и отличный способ работы с ограничениями. Благодарю. –

0

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

0

В ответ на ваш вопрос: «Я хочу сбросить все данные и сохранить последние 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 дней данные, доступные