Tôi có một bảng lưu trữ các cuộc hẹn có sẵn cho giáo viên, cho phép hai loại chèn:
Dựa trên hàng giờ : với toàn quyền tự do thêm các vị trí không giới hạn mỗi ngày cho mỗi giáo viên (miễn là các vị trí không trùng nhau): vào ngày 15 tháng Tư, một giáo viên có thể có các vị trí vào lúc 10:00, 11:00, 12:00 và 16:00 . Một người được phục vụ sau khi chọn thời gian / thời gian dành cho giáo viên cụ thể.
Khoảng thời gian / phạm vi : vào ngày 15 tháng Tư, một giáo viên khác có thể làm việc từ 10:00 đến 12:00 và sau đó từ 14:00 đến 18:00. Một người được phục vụ theo thứ tự đến, vì vậy nếu một giáo viên làm việc từ 10:00 đến 12:00, tất cả những người đến trong giai đoạn này sẽ được tham dự theo thứ tự đến (xếp hàng địa phương).
Vì tôi phải trả lại tất cả các giáo viên có sẵn trong một tìm kiếm, tôi cần tất cả các vị trí được lưu trong cùng một bảng với thứ tự các phạm vi đến. Bằng cách này, tôi có thể đặt hàng theo date_from ASC, hiển thị các vị trí có sẵn đầu tiên trước tiên trên kết quả tìm kiếm.
Cấu trúc bảng hiện tại
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;
Truy vấn tìm kiếm
Tôi cần lọc theo: datetime thực tế, city_id, topic_id và nếu có sẵn một vị trí (status = 0).
Đối với hàng giờ, tôi phải hiển thị tất cả các vị trí có sẵn cho ngày có sẵn gần nhất cho mỗi giáo viên (hiển thị tất cả các vị trí thời gian của một ngày nhất định và không thể hiển thị nhiều hơn một ngày cho cùng một giáo viên). (Tôi đã nhận được truy vấn với sự giúp đỡ từ mattedgod ).
Đối với phạm vi dựa trên (order_of_ariances = 1), tôi phải hiển thị phạm vi khả dụng gần nhất, chỉ một lần cho mỗi giáo viên.
Truy vấn đầu tiên chạy riêng lẻ trong khoảng 0,10 ms, truy vấn thứ hai 0,08 ms và UNION ALL trung bình 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;
Câu hỏi
Có cách nào để tối ưu hóa UNION, vì vậy tôi có thể nhận được phản hồi hợp lý ở mức tối đa ~ 20ms hoặc thậm chí trả về phạm vi dựa trên + hàng giờ chỉ trong một truy vấn (với IF, v.v.) không?
Câu đố về SQL: http://www.sqlfiddle.com/#!2/59420/1/0
BIÊN TẬP:
Tôi đã thử một số tính không chuẩn hóa bằng cách tạo trường "only_date_from" nơi tôi chỉ lưu trữ ngày, vì vậy tôi có thể thay đổi ...
DATE(MIN(date_from)) as closestDay / DATE(teacher_slots.date_from) = closestDay
... đến đây
MIN(only_date_from) as closestDay / teacher_slots.only_date_from = closestDay
Nó đã giúp tôi tiết kiệm 100ms! Vẫn trung bình 200ms.