Как уменьшить нагрузку на Mysql запрос на очень нагруженной базе?

привет всем! Пишу повторно. Отчасти вопрос решили, но остались непонятки.
Есть серьезно нагруженный проект.
Есть репликация (пишем в мастер, читаем со слейвов)
Есть 2 таблицы, в которые идет огромное количество записей и огромное количество инсертов и огромное кличество чтений (Task и TaskFlow2). Таблицы огромные.
И есть селект, с которым проблемы.
Индексы все сделаны.
SELECT 
  task.id, 
  task.remains
FROM 
  Task task 
WHERE 
  task.status = 'active' 
  AND task.type = 'follow_profile' 
  AND task.provider = 'insta' 
  AND task.cat = 3 
  AND NOT EXISTS(
  SELECT 1 FROM  TaskFlow flow 
  WHERE 
    flow.url_id = task.url_id 
    AND flow.executor_acc_id = $acc 
  );
ORDER BY task.id ASC
LIMIT 300

Индексы:

Task ( status, type, provider, cat )
TaskFlow (executor_acc_id, url_id )

Суть: При количестве запросов селект и инсерт в них примерно 3000+ в секунду, все ок.
Как только количество переваливает за 4000+ начинает сильно расти нагрузка на процессоры слейвов, селекты начинают выполнятся с задержкой в статусе sending data и их копится огромное количество если смотреть по show processlist и начинает расти отставание между мастером и слейвом. Соответственно все тупит и работает некорректно.
Не прекращается пока не ограничить поступление запросов. Как только останавливаем инсерты и селекты, все за пару секунд возвращается в норму

Подскажите куда копать. Спасибо!

UPD: Если увеличивать LIMIT в выборке, нагрузка значительно возрастает.
  • Вопрос задан
  • 679 просмотров
Пригласить эксперта
Ответы на вопрос 5
@rPman
ты уже задавал этот вопрос, думаешь больше информации тебе придумают?
раз тормозит слейв, то почему бы не решить проблему грубой силой и поставить второй, третий.. десятый, а свои запросы делай на тот слейв, что менее нагружен в данный момент или тупо по очереди

p.s. какой объем данных? не будет ли эффективнее реализовать свои таски в оперативной памяти своего отдельного приложения, и вместо базы данных пусть твой бакэенд (или кто там) лезет к этому приложений... ни одна sql база данных ни при каких условиях не будет работать быстрее, чем твое собственное приложение с данными в оперативной памяти, а уж если тебе хватит одного потока то и на разработку решения потратишь очень мало времени
Ответ написан
@Drno
Объем базы какой?
Возможно глупый вариант - но можно сделать раздел диска из оперативки... быстрее некуда.
Как раз копией
А сбрасывать в основу уже постепенно. И готовое...

Ну или запилить в рейд кучу ssd....
Ответ написан
XXXXPro
@XXXXPro
Fullstack Web developer
Судя по всему, проблема в том, что MySQL начинает не успевать перестраивать индексы.
Сразу возникает вопрос: status, type, provider — это ENUMы или VARCHARы? Если второе, то можно ли заменить их на ENUM? Если нет, то можно попробовать делать индекс не по полному полю, а по его ограниченной длине, например, Task ( status(4), type(8), provider(4), cat ). В этом случае индексы будут перестраиваться быстрее.
Другой вариант вариант — сделать дополнительное численное поле, которое будет хешем от строкового значения, и делать выборку по нему. Можно использовать даже самую обычную CRC32 и сравнивать так WHERE status_crc=CRC32('active') AND type_crc=CRC32('follow_profile'). Соответственно, индексы делать не по status и type, а по status_crc и type_crc (по численным полям индексы строятся быстрее, чем по строковым).
Ещё вариант — сделать в своём коде возможность буферизовать и накапливать накапливать какое-то количество INSERTов, после чего делать DISABLE KEYS, выполнять накопившиеся INSERT, затем ENABLE KEYS.
Ответ написан
@edo1h
Без каких-то серьёзных ахитектурных изменений вас спасёт только партицирование на несколько серверов, чтобы на каждом была только часть таблицы.
Ответ написан
Комментировать
LaRN
@LaRN
Senior Developer
Можно попробовать сделать небольшую нормализации, например перенести из таблицы task три поля ( type, provider, cat ) в отдельную таблицу tasktype, а в исходной таблице оставить только одно поле tasktypeID и это поле поместить в индекс таблицы task вместо предыдущих трех.
Т.к. у вас запросе условия указаты статичными, то можно вначале наиграть tasktypeID по таблице tasktype, которая не должна быть очень большой и затем идти в индекс от task по двум полям вместо четырёх. Кроме этого индекс в task станет меньше места занимать и это должно ускорить поиск по индексу и его перестраивание при добавлении новых строк.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы