교사를위한 가능한 약속을 저장하는 테이블이 있는데 두 가지 종류의 삽입이 가능합니다.
시간별 : 교사 당 하루에 무제한 슬롯을 추가 할 수있는 자유 (슬롯이 겹치지 않는 한) : 15/4 월 교사는 10:00, 11:00, 12:00 및 16:00에 슬롯을 가질 수 있습니다. . 특정 교사 시간 / 슬롯을 선택한 후 사람에게 서비스가 제공됩니다.
기간 / 범위 : 15/4 월 4 월 다른 교사는 10 : 00 ~ 12 : 00에 14 : 00 ~ 18 : 00에 일할 수 있습니다. 도착 순서대로 한 사람이 서비스되므로 교사가 10시에서 12 시까 지 근무하는 경우이 기간에 도착한 모든 사람은 도착 순서 (현지 대기열)로 참석합니다.
검색 할 때 사용 가능한 모든 교사를 반환해야하므로 도착 범위 순서와 동일한 테이블에 모든 슬롯을 저장해야합니다. 이렇게하면 date_from 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;
검색어
실제 날짜 시간, city_id, subject_id 및 슬롯을 사용할 수 있는지 여부 (상태 = 0)로 필터링해야합니다.
들어 시간당 기반 나는 모든 교사에 대한 첫 번째 가장 가까운 가능한 일에 대한 모든 사용 가능한 슬롯을 표시해야한다 (주어진 하루의 모든 시간 슬롯을 표시하고 같은 교사 하루 이상 표시 할 수 없습니다). ( mattedgod 의 도움으로 쿼리를 얻었 습니다 ).
대한 기반 범위 (order_of_arrival = 1), 나는 가장 가까운 가능한 범위, 교사 당 한 시간을 표시해야합니다.
첫 번째 쿼리는 약 0.10ms, 두 번째 쿼리는 0.08ms, UNION ALL은 평균 300ms에서 개별적으로 실행됩니다.
(
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을 최적화하는 방법이 있습니까? 그래서 최대 ~ 20ms의 합리적인 응답을 얻거나 심지어 하나의 쿼리 (IF 등으로)를 기준으로 + 시간당 반환 범위를 얻을 수 있습니까?
SQL 피들 : 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
이미 100ms를 절약했습니다! 여전히 평균 200ms입니다.