Как оптимизировать запрос на удаление с помощью подвыбора? - PullRequest
0 голосов
/ 10 января 2019

Этот запрос должен удалить более 17 миллионов строк из таблицы, содержащей 20 миллионов.

DELETE
FROM statements
WHERE agreement_id IN
    (SELECT id
     FROM agreements
     WHERE created < DATE_SUB(CURDATE(), INTERVAL 6 MONTH));


DELETE
FROM agreements
WHERE created < DATE_SUB(CURDATE(), INTERVAL 6 MONTH)

Требуются часы, чтобы бежать, я что-то упускаю, что может немного ускорить процесс?

Самостоятельный отбор занимает несколько секунд, я не понимаю, почему удаление занимает так много времени.

Ответы [ 3 ]

0 голосов
/ 11 января 2019

Попробуйте переписать первый оператор для использования EXISTS.

DELETE FROM statements
            WHERE EXISTS (SELECT *
                                 FROM agreements
                                 WHERE agreements.id = statements.aggreement_id
                                       AND agreements.created < date_sub(curdate(), interval 6 month));

И поставить индекс на agreements (id, created) (если его там еще нет).

CREATE INDEX agreements_id_created
             ON agreements
                (id,
                 created);

Для второго создайте индекс для agreements (created) (если его там еще нет).

CREATE INDEX agreements_created
             ON agreements
                (created);
0 голосов
/ 11 января 2019

Используйте «удаление нескольких таблиц» вместо обычно неэффективных IN ( SELECT ... ).

Обсуждается несколько методов больших удалений здесь .

Чтобы удалить 85% таблицы, действительно лучше построить новую таблицу с 15%, которые вы держите, а затем поменять таблицу на место. (Подробнее об этом в ссылке выше.)

0 голосов
/ 10 января 2019

Если у вас есть много удалений, которые нужно предпринять. Я предлагаю вам:

  1. создать новую временную таблицу с данными, которые останутся.
  2. Обрезать основную таблицу
  3. Переместить данные из временной таблицы в основную таблицу

или

  1. создать новую временную таблицу с данными, которые останутся.
  2. Оставь свой главный стол
  3. Переименуйте вашу временную таблицу в основную (не забудьте создать ограничения)

Также по вашему запросу,

никогда не используйте предложение IN для БОЛЬШИХ данных. Вместо этого существует использование, которое является более производительным.

Базовый скрипт:

CREATE TABLE tmp_statements as
  SELECT * FROM statements s where exists 
  (
     select 1 FROM agreements a 
     WHERE 
       created < DATE_SUB(CURDATE(), INTERVAL 6  MONTH AND
       s.agreement_id = a.agreement_id
  ));

 DROP TABLE statements;

 RENAME TABLE tmp_statements TO statements ;

 --DONT FORGET TO RECREATE  CREATE YOUR INDEXES, CONSTRAINTS;
...