Долгое выполнение запросов в 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: Огромное спасибо всем за советы, каждый совет хороший, поэтому лучшего ответа выбрать не могу, всех поблагодарил за помощь в профиле.
  • Вопрос задан
  • 7595 просмотров
Пригласить эксперта
Ответы на вопрос 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
Материализуйте результат запроса. Заведите отдельную таблицу, при поступлении задач вставляйте, при назначении удаляйте.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы