Делаю проект, в котором можно выполнять/скрывать задания.
Всё работало шустро, но позже я решил добавить 300 000 записей в таблицу заданий и по 100 000 в таблицы tasks_done и tasks_hide.
Результат: время выполнения - 1.2 сек (Если добавить SQL_NO_CACHE, с ним +-), что не очень хорошо.
Для получения заданий использую вот такой запрос:
SELECT id, name, status, price ...
FROM `tasks`
WHERE `tasks`.id NOT IN (
SELECT `task_id`
FROM `tasks_done`
WHERE `user_id` = 5
)
AND `tasks`.id NOT IN (
SELECT `task_id`
FROM `tasks_hide`
WHERE `user_id` = 5
)
AND `status` =1
ORDER BY `price` DESC
LIMIT 0 , 100
CREATE TABLE IF NOT EXISTS `tasks` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`status` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
`price` int(11) NOT NULL
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=315426;
CREATE TABLE IF NOT EXISTS `tasks_done` (
`task_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL
UNIQUE KEY `task_id_user_id` (`task_id`,`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `tasks_hide` (
`task_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
UNIQUE KEY `task_id_user_id` (`task_id`,`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE tasks ADD INDEX (status,price);
Добавьте в таблицу tasks еще один статус (один у вас есть, но непонятно зачем он нужен). Пусть это будет поле status1, имеющее значение 0 - если задание не скрыто и не выполненно, 1 - если скрыто, 2 - если выполненно. Теперь можно брать не скрытые и не выполненные задания просто по статусу, отбросив сразу два подзапроса.
Вы explain запроса делали?
Использовать просто IN не очень то рекомендуют, а у вас вообще IN (SELECT ...)
Сделайте explain вашего запроса и смотрите сколько затронуто строк. В вашем случае это будет несколько млн сортировок.
Делайте как вам рекомендуют выше. Добавьте поле в tasks и делайте его индексом. Поле делайте tinyint или set('done','hide') что бы не занимало много места.
ALTER table tasks ADD index test_index (`id`, `status`, `price`, `name`);
CREATE TABLE IF NOT EXISTS `tasks_status` (
`task_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`status` int(1) NOT NULL,
UNIQUE KEY `task_id_user_id` (`task_id`,`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;