У меня есть таблица, в которой хранятся доступные встречи для учителей, позволяющие вставлять два вида:
На почасовой основе : с полной свободой добавлять неограниченное количество слотов в день на учителя (если слоты не перекрываются): 15 апреля преподаватель может иметь слоты в 10:00, 11:00, 12:00 и 16:00. , Человек обслуживается после выбора определенного времени учителя / слота.
Период времени / диапазон : 15 апреля другой преподаватель может работать с 10:00 до 12:00, а затем с 14:00 до 18:00. Лицо обслуживается по порядку прибытия, поэтому, если учитель работает с 10:00 до 12:00, все лица, прибывающие в этот период, будут сопровождаться порядком прибытия (местная очередь).
Так как я должен вернуть всех доступных учителей в поиске, мне нужно, чтобы все слоты были сохранены в той же таблице, что и диапазоны порядка прибытия. Таким образом, я могу заказать по дате от ASC, показывая первые доступные слоты первыми в результатах поиска.
Текущая структура таблицы
CREATE TABLE `teacher_slots` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`teacher_id` mediumint(8) unsigned NOT NULL,
`city_id` smallint(5) unsigned NOT NULL,
`subject_id` smallint(5) unsigned NOT NULL,
`date_from` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`date_to` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`status` tinyint(4) NOT NULL DEFAULT '0',
`order_of_arrival` tinyint(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `by_hour_idx` (`teacher_id`,`order_of_arrival`,`status`,`city_id`,`subject_id`,`date_from`),
KEY `order_arrival_idx` (`order_of_arrival`,`status`,`city_id`,`subject_id`,`date_from`,`date_to`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Поисковый запрос
Мне нужно отфильтровать по: фактическому datetime, city_id, subject_id и, если слот доступен (status = 0).
Для почасовой оплаты я должен показать все доступные слоты на первый ближайший доступный день для каждого учителя (показать все временные интервалы данного дня и не может показывать более одного дня для одного и того же учителя). (Я получил запрос с помощью mattedgod ).
Для основанного на диапазоне (order_of_arrival = 1) я должен показать самый близкий доступный диапазон, только один раз на учителя.
Первый запрос выполняется индивидуально примерно за 0,10 мс, второй запрос - 0,08 мс, а UNION ALL - в среднем за 300 мс.
(
SELECT id, teacher_slots.teacher_id, date_from, date_to, order_of_arrival
FROM teacher_slots
JOIN (
SELECT DATE(MIN(date_from)) as closestDay, teacher_id
FROM teacher_slots
WHERE date_from >= '2014-04-10 08:00:00' AND order_of_arrival = 0
AND status = 0 AND city_id = 6015 AND subject_id = 1
GROUP BY teacher_id
) a ON a.teacher_id = teacher_slots.teacher_id
AND DATE(teacher_slots.date_from) = closestDay
WHERE teacher_slots.date_from >= '2014-04-10 08:00:00'
AND teacher_slots.order_of_arrival = 0
AND teacher_slots.status = 0
AND teacher_slots.city_id = 6015
AND teacher_slots.subject_id = 1
)
UNION ALL
(
SELECT id, teacher_id, date_from, date_to, order_of_arrival
FROM teacher_slots
WHERE order_of_arrival = 1 AND status = 0 AND city_id = 6015 AND subject_id = 1
AND (
(date_from <= '2014-04-10 08:00:00' AND date_to >= '2014-04-10 08:00:00')
OR (date_from >= '2014-04-10 08:00:00')
)
GROUP BY teacher_id
)
ORDER BY date_from ASC;
Вопрос
Есть ли способ оптимизировать UNION, чтобы я мог получить разумный ответ максимум ~ 20 мс или даже диапазон возврата на основе + ежечасно на основе только одного запроса (с IF и т. Д.)?
SQL Fiddle: http://www.sqlfiddle.com/#!2/59420/1/0
РЕДАКТИРОВАТЬ:
Я попытался немного денормализовать, создав поле "only_date_from", где я сохранил только дату, чтобы я мог изменить это ...
DATE(MIN(date_from)) as closestDay / DATE(teacher_slots.date_from) = closestDay
... к этому
MIN(only_date_from) as closestDay / teacher_slots.only_date_from = closestDay
Это уже спасло меня 100 мс! Еще 200 мс в среднем.