Выполнение запроса MySQL JOIN занимает слишком много времени

#mysql #query-optimization

#mysql #оптимизация запроса

Вопрос:

У меня есть таблица под названием users, в которой содержится примерно 250 000 записей. У меня есть еще одна таблица под названием staging, в которой содержится около 75 000 записей. В промежуточной версии есть только один столбец, msisdn. Я хочу проверить, сколько строк в промежуточном режиме отсутствуют в users.

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

 SELECT
    s.*
    FROM staging s
        LEFT OUTER JOIN users u ON u.msisdn=s.msisdn
        WHERE u.msisdn IS NULL
  

Однако проблема заключается в том, что я пытаюсь выполнить этот запрос для полного списка из 250 тыс. пользователей. Он выполнялся в течение часа, прежде чем я его остановил. Могу ли я каким-либо образом оптимизировать этот запрос?

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

 SELECT
    s.*
    FROM staging s
        LEFT OUTER JOIN users u ON u.msisdn=s.msisdn
        WHERE u.msisdn IS NULL
    LIMIT 0,10000
  

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

Комментарии:

1. Пожалуйста, запустите свой запрос с объяснением и опубликуйте результат. Проиндексированы ли оба столбца msisdn? Если это так, запустите OPTIMIZE TABLE для обеих таблиц.

Ответ №1:

Во-первых, вы можете увидеть, какие индексы использует MySQL, с помощью команды EXPLAIN. Просто напишите EXPLAIN перед вашим запросом, и результаты покажут, какой индекс (если он есть) он использует. Предположительно, если он выполняется так медленно для такого (относительно) небольшого набора данных, как 250 000 записей, он использует не очень эффективный индекс, и вы сможете увидеть, где именно.

Также может помочь переписать запрос как NOT EXISTS вот так:

 SELECT s.* FROM staging s
WHERE NOT EXISTS (SELECT 1 FROM users WHERE users.misdn = s.misdn)
  

Ответ №2:

Поместите индексы в msisdn столбцы каждой таблицы. Поскольку это не PK на users , вам нужно поместить в него некластеризованный индекс. Это должно значительно ускорить ваш запрос.

Ответ №3:

Что вы можете сделать, чтобы ускорить этот запрос:

  • убедитесь, что msisdn проиндексирован в обеих таблицах
  • оптимизируйте свои таблицы
  • замените * на msisdn

Ответ №4:

Я не уверен, насколько это будет быстрее, но вы можете попробовать что-то вроде.

 select msisdn
from staging
where msisdn not in (select msisdn from users)
  

Кроме того, убедитесь, что для столбца msisdn в обеих таблицах существует индекс. Это должно значительно ускорить процесс.