Задать вопрос

Долгое выполнение запросов в MySQL

Добрый день.
Неожиданно для меня, один из проектов стал очень быстро развиваться и сейчас встала проблема с базой данных.
Используется связка PHP + MySQL.

Есть таблица, в ней уже ~20 млн записей %)
Структура таблицы:

+---------+---------------+------+-----+---------+-------+
| Field   | Type          | Null | Key | Default | Extra |
+---------+---------------+------+-----+---------+-------+
| task_id | int(9)        | NO   | PRI | NULL    |       |
| user_id | int(9)        | NO   | PRI | NULL    |       |
| checked | enum('0','1') | NO   | MUL | 0       |       |
| taken   | enum('0','1') | NO   | MUL | 0       |       |
+---------+---------------+------+-----+---------+-------+


Запрос:
SELECT DISTINCT `task_id` FROM `tasks_pending` WHERE `checked`='0' AND `taken`='0' LIMIT 50;

Проблема в том, что время выполнения запросов очень большое, ~3 минут, что недопустимо.

Начитался про индексы, расставил все что мог:
image

Первый индекс (task_id) убирать нельзя, он в основе лежит.
Машина довольно мощная и думаю, что должна тянуть быстрее: Intel® Core™ i7-2600, RAM: 16 GB, вся таблица должна влезать целиком.

Машина настраивалась скриптом mysqltuner, всегда его использовал и не испытывал проблем, пока не столкнулся с High-Load'ом.

EXPLAIN говорит следующее: скриншот, потому что не влезает
Подскажите пожалуйста, что я сделал неверно и как это исправить? Спасибо.

UPD: Огромное спасибо всем за советы, каждый совет хороший, поэтому лучшего ответа выбрать не могу, всех поблагодарил за помощь в профиле.
  • Вопрос задан
  • 7724 просмотра
Подписаться 17 Оценить Комментировать
Пригласить эксперта
Ответы на вопрос 7
rakot
@rakot
Попробуйте составной ключ checked, taken, task_id. Именно в таком порядке, может помочь. А вообще какая таблица InnoDB?
Ответ написан
AGvin
@AGvin
Вы используете DISTINCT, что само по себе плохо.

«Если LIMIT # указывается совместно с DISTINCT, MySQL остановится, как только найдет # уникальных строк.»

Советую прочитать про то, как MySQL оптимизирует DISTINCT:
Ответ написан
CKOPOBAPKuH
@CKOPOBAPKuH
task_id_2 лишний, запрос который будет его использовать точно так же сможет использовать первую половину первичного индекса. так что task_id_2 дублирующий и его нужно убрать
индексы отдельно на checked и отдельно на taken не очень полезны.
индекс по (checked, taken, task_id) который вам посоветовал первый комментатор — действительно имеет смысл попробовать.
Ответ написан
Комментировать
script88
@script88
1. Покажите конфиг MySQL,
2. Одним mysqltuner Вам не обойтись
3. Советую заменить MySQL на Perocona Server.
Ответ написан
@edogs
Попробуйте повесить составной индекс на checked,taken или даже на task_id, checked,taken
а запрос можно попробовать поменять на запрос вида
select task_id from tasks_pending where checked=0 and taken=0 group by task_id limit 50;
Ответ написан
@myadzel
Замените ENUM на INT(1) UNSIGNED, забудьте про ENUM.
Ответ написан
@ComodoHacker
Материализуйте результат запроса. Заведите отдельную таблицу, при поступлении задач вставляйте, при назначении удаляйте.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

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