Самый быстрый способ удалить огромную таблицу MySQL - PullRequest
51 голосов
/ 18 мая 2009

У меня огромная база данных MySQL (InnoDB) с миллионами строк в таблице сеансов, которые были созданы несвязанным, неработающим сканером, работающим на том же сервере, что и наш. К сожалению, сейчас я должен исправить ситуацию.

Если я попытаюсь truncate table sessions;, это займет слишком много времени (более 30 минут). Я не забочусь о данных; Я просто хочу как можно быстрее стереть стол. Есть ли более быстрый способ, или мне придется просто выложить его на ночь?

Ответы [ 11 ]

126 голосов
/ 15 июня 2011

(Так как это оказалось высоко в результатах Google, я подумал, что может пригодиться немного больше инструкций).

MySQL имеет удобный способ создания пустых таблиц, таких как существующие таблицы, и команду переименования атомарной таблицы. Вместе это быстрый способ очистки данных:

CREATE TABLE new_foo LIKE foo;

RENAME TABLE foo TO old_foo, new_foo TO foo;

DROP TABLE old_foo;

Готово

47 голосов
/ 18 мая 2009

Самый быстрый способ - использовать DROP TABLE, чтобы полностью отбросить таблицу и воссоздать ее, используя то же определение. Если у вас нет ограничений по внешнему ключу в таблице, вам следует это сделать.

Если вы используете версию MySQL более 5.0.3, это будет происходить автоматически с TRUNCATE. Вы также можете получить некоторую полезную информацию из руководства, в которой описано, как TRUNCATE работает с ограничениями FK. http://dev.mysql.com/doc/refman/5.0/en/truncate-table.html

EDIT: TRUNCATE - это не то же самое, что капля или DELETE FROM. Для тех, кто смущен из-за различий, пожалуйста, проверьте ссылку на руководство выше. TRUNCATE будет действовать так же, как и сброс, если он может (если нет FK), в противном случае он действует как DELETE FROM без предложения where.

7 голосов
/ 19 мая 2009

Лучший способ сделать это с MySQL - это:

DELETE from table_name LIMIT 1000;

или 10000 (в зависимости от того, как быстро это происходит).

Поместите это в цикл, пока все строки не будут удалены.

Пожалуйста, попробуйте это, так как оно действительно будет работать. Это займет некоторое время, но это сработает.

7 голосов
/ 18 мая 2009

Не могли бы вы взять схему, отбросить таблицу и воссоздать ее?

3 голосов
/ 18 мая 2009

drop table должен быть самым быстрым способом избавиться от него.

1 голос
/ 20 мая 2009

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

Усечение эффективно так же эффективно, как и очистка таблицы, но вам может потребоваться удалить ссылки на внешние ключи, если вы не хотите, чтобы эти таблицы также очищались.

1 голос
/ 18 мая 2009

Если вы просто хотите полностью избавиться от стола, почему бы просто не сбросить это?

1 голос
/ 18 мая 2009

Вы пытались использовать "падение"? Я использовал его на столах размером более 20 ГБ, и он всегда завершается за секунды.

0 голосов
/ 02 марта 2017

ответ Searlea хорош, но, как указано в комментариях, вы теряете внешние ключи во время боя. это решение аналогично: усечение выполняется за секунду, но вы сохраняете внешние ключи.

Хитрость в том, что мы отключаем / включаем проверки FK.

SET FOREIGN_KEY_CHECKS=0;
CREATE TABLE NewFoo LIKE Foo;
insert into NewFoo SELECT * from Foo where What_You_Want_To_Keep  

truncate table Foo;
insert into Foo SELECT * from NewFoo;
SET FOREIGN_KEY_CHECKS=1;

Расширенный ответ - Удалить все, кроме некоторых строк

Моя проблема заключалась в следующем: Из-за сумасшедшего скрипта в моей таблице было 7.000.000 ненужных строк. Мне нужно было удалить 99% данных в этой таблице , поэтому мне нужно было скопировать То, что я хочу сохранить в таблицу tmp перед удалением.

Эти строки Foo, которые мне нужно было хранить, зависели от других таблиц с внешними ключами и индексами.

что-то в этом роде:

insert into NewFoo SELECT * from Foo where ID in (
 SELECT distinct FooID from TableA 
 union SELECT distinct FooID from TableB 
 union SELECT distinct FooID from TableC
)

но этот запрос всегда прерывался через 1 час. Поэтому я должен был сделать это так:

CREATE TEMPORARY TABLE tmpFooIDS  ENGINE=MEMORY  AS (SELECT distinct FooID from TableA);
insert into tmpFooIDS SELECT distinct FooID from TableB
insert into tmpFooIDS SELECT distinct FooID from TableC
insert into NewFoo SELECT * from Foo where ID in (select ID from tmpFooIDS);

Я считаю, что поскольку индексы настроены правильно, я думаю, что оба способа заполнения NewFoo должны были быть одинаковыми, но на практике это не так.

Вот почему в некоторых случаях вы можете сделать так:

SET FOREIGN_KEY_CHECKS=0;
CREATE TABLE NewFoo LIKE Foo;

-- Alternative way of keeping some data.
CREATE TEMPORARY TABLE tmpFooIDS  ENGINE=MEMORY  AS (SELECT * from Foo where What_You_Want_To_Keep);
insert into tmpFooIDS SELECT ID from Foo left join Bar where OtherStuff_You_Want_To_Keep_Using_Bar
insert into NewFoo SELECT * from Foo where ID in (select ID from tmpFooIDS);

truncate table Foo;
insert into Foo SELECT * from NewFoo;
SET FOREIGN_KEY_CHECKS=1;
0 голосов
/ 20 мая 2009

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

...