MySQL настройка производительности для запроса DELETE - PullRequest
2 голосов
/ 19 февраля 2020

Может ли кто-нибудь помочь мне переписать запрос, чтобы ускорить время выполнения? Для выполнения потребовалось 37 секунд.

DELETE FROM storefront_categories 
WHERE userid IN (SELECT userid 
                FROM MASTER 
                where expirydate<'2020-2-4' 
                )

В то же время этот запрос выполнялся всего за 4,69 секунды.

DELETE FROM storefront_categories 
WHERE userid NOT IN (SELECT userid FROM MASTER)

Таблица storefront_categories имеет 97K записей, где, как в MASTER , есть 40K записей. Мы создали индекс для поля MASTER.expirydate.

Ответы [ 4 ]

1 голос
/ 19 февраля 2020

Я бы попробовал с exists:

DELETE 
FROM storefront_categories 
WHERE EXISTS (SELECT 1 
              FROM MASTER M 
              WHERE M.userid = storefront_categories.userid AND
                    M.expirydate <'2020-02-04'  
              );

Здесь будет индекс, я бы ожидал индекс на storefront_categories(userid) & MASTER(userid, expirydate).

1 голос
/ 19 февраля 2020

Я бы посоветовал вам использовать NOT EXISTS с правильным индексом:

DELETE sc
    FROM storefront_categories sc
    WHERE NOT EXISTS (SELECT 1
                      FROM master m
                      WHERE m.userid = sc.userid AND
                            m.expirydate < '2020-02-04' 
                     );

Требуемый индекс находится на master(userid, expirydate). Порядок столбцов важен. Для этой версии индекс на storefront_categories не помогает.

Обратите внимание, что я изменил формат даты. Я рекомендую использовать YYYY-MM-DD, чтобы избежать двусмысленности - и использовать все 10 символов.

1 голос
/ 19 февраля 2020

Запрос выглядит нормально как есть.

Я бы предложил следующие индексы для оптимизации:

master(expiry_date, userid)
storefront_categories(userid)

Первый индекс - это , охватывающий индекс для подзапрос в master: это означает, что база данных должна быть в состоянии выполнить подзапрос, просматривая только индекс (тогда как в индексе просто expiry_date, ей все равно нужно просматривать данные таблицы, чтобы выбрать связанный userid).

Второй индекс позволяет базе данных оптимизировать операцию in.

0 голосов
/ 19 февраля 2020

При удалении строк 40 КБ ожидайте, что это займет время. Основная стоимость (при условии адекватной индексации и достойного запроса) - это накладные расходы на транзакционную семантику удаления «atomi c». Это включает в себя создание копии каждой удаляемой строки, на случай, если есть cra sh. Таким образом, InnoDB может вернуть базу данных к тому, что было до появления cra sh.

. При удалении 40% таблицы намного быстрее копировать строки, чтобы сохранить их в другой таблице, а затем выполнить обмен таблицы.

При удалении большого количества строк (независимо от процентного соотношения) лучше делать это порциями. И лучше всего пройтись по таблице на основе PRIMARY KEY.

. Я обсуждаю оба этих метода, а также другие, в http://mysql.rjweb.org/doc.php/deletebig

Что касается формулировка запроса:

  • Зависит от версии; старые версии MySQL плохо работали с некоторыми разновидностями.
  • NOT IN (SELECT ...) и NOT EXISTS имеют тенденцию быть худшими.
  • IN (SELECT ...) и / или EXISTS могут быть лучше.
  • "Multi-table DELETE - это еще один вариант. Он работает как JOIN.
  • (Итог: вы не сказали, какую версию вы используете; я могу ' не могу предсказать, какая формулировка будет наилучшей.)
  • Мой блог избегает дебатов по формулировке.
...