Mysql - Удаление строк из InnoDB происходит очень медленно

Я получил базу данных mysql с ок. 1 ТБ данных. Таблица fuelinjection_stroke имеет ок. 1.000.000.000 строк. DBID - это первичный ключ, который автоматически увеличивается на единицу с каждой вставкой.

Я пытаюсь удалить первые 1.000.000 строк, используя очень простой оператор:

Delete from fuelinjection_stroke where DBID < 1000000;

Этот запрос занимает очень много времени ( > 24 часа) на моем выделенном сервере 8core Xeon (32 ГБ памяти, хранилище SAS).

Любая идея, можно ли ускорить процесс?

Ответ 1

Я считаю, что таблица закрывается. Я столкнулся с такой же проблемой и узнал, что можно быстро удалить записи 10k. Таким образом, вы можете написать простую программу script/, которая удалит записи кусками.

   DELETE FROM fuelinjection_stroke WHERE DBID < 1000000 LIMIT 10000;

И продолжайте выполнять его, пока он не удалит все

Ответ 2

Вы лишены пространства? Возможно ли время простоя?

Если нет, вы можете поместиться в новый столбец INT длиной 1 и по умолчанию использовать значение 1 для "active" (или независимо от вашей терминологии) и 0 для "неактивного". Фактически, вы могли бы использовать от 0 до 9 как 10 различных состояний, если это необходимо.

Добавление этого нового столбца займет время looooooooong, но как только вы закончите, ваши UPDATE должны быть молниеносно, пока вы делаете это с PRIMARY (как и с вашим DELETE), и вы не индексируете этот новый столбец.

Причина, по которой InnoDB занимает столько времени, чтобы УДАЛИТЬ на такой массивной таблице, как ваша, из-за индекса кластера. Он физически заказывает ваш стол на основе вашего PRIMARY (или первого УНИКАЛЬНОГО, который он находит... или как ему кажется, если он не может найти PRIMARY или UNIQUE), поэтому, когда вы вытаскиваете один ряд, он теперь полностью переупорядочивает вашу ENTRE таблицу диск для скорости и дефрагментации. Так что это не DELETE, что так долго. Это физическое переупорядочение после удаления этой строки.

Когда вы создаете новый столбец INT со значением по умолчанию, пробел будет заполнен, поэтому, когда вы ОБНОВЛЯЕТ его, нет необходимости в физическом переупорядочении по вашей огромной таблице.

Я точно не знаю, что такое ваша схема, но использование столбца для состояния строки намного быстрее, чем DELETEing; однако это займет больше места.

Попробуйте установить значения:

innodb_flush_log_at_trx_commit=2
innodb_flush_method=O_DIRECT (for non-windows machine)
innodb_buffer_pool_size=25GB (currently it is close to 21GB)
innodb_doublewrite=0
innodb_support_xa=0
innodb_thread_concurrency=0...1000 (try different values, beginning with 200)

Литература:

MySQL docs для описания разных переменных.

Настройка настройки сервера MySQL

Основы оптимизации производительности MySQL

http://bugs.mysql.com/bug.php?id=28382

Ответ 3

Какие индексы у вас есть?

Я думаю, что ваша проблема заключается в том, что delete перестраивает индекс на каждой итерации.

Я бы удалил индексы, если они есть, удалить, а затем снова добавить индексы. Это будет намного быстрее (я думаю).

Ответ 4

Ваша база данных может проверять записи, которые необходимо изменить в чужом ключе (каскады, удаление).

Но ответ I-Conica - хорошая точка (+1). Процесс удаления одной записи и обновления большого количества индексов в течение 100 000 раз неэффективен. Просто снимите индекс, удалите все записи и создайте его снова.

И, конечно, проверьте, есть ли какая-либо блокировка в базе данных. Один пользователь или приложение может заблокировать запись или таблицу, и ваш запрос будет ждать, пока пользователь не выпустит ресурс или не достигнет таймаута. Один из способов проверить, действительно ли ваша база данных выполняет настоящую работу или просто ждать, - это запрос из соединения, которое устанавливает параметр --innodb_lock_wait_timeout на несколько секунд. Если это не удается, по крайней мере, вы знаете, что запрос в порядке, и вам нужно найти и повторно открыть эту блокировку. Примерами блокировок являются Select * from XXX. Для обновлений и незавершенных транзакций.

Ответ 5

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

create table keepers
select * from origTable where {clause to retrieve rows to preserve};
truncate table origTable;
insert into origTable null,keepers.col2,...keepers.col(last) from keepers;
drop table keepers;

Около 2,2 миллиона строк были обработаны примерно за 3 минуты.

Ответ 6

Я не знаю точных сообщений для ur que. Но, написав еще один способ удаления этих строк, попробуйте это.

delete from fuelinjection_stroke where DBID in
(
    select top 1000000 DBID  from fuelinjection_stroke 
    order by DBID asc
)