ฉันมีตารางที่จัดเก็บการนัดหมายที่มีให้สำหรับครูช่วยให้สามารถแทรกได้สองชนิด:
ตามชั่วโมง : มีอิสระทั้งหมดในการเพิ่มช่องไม่ จำกัด ต่อวันต่อครู (ตราบใดที่ช่องไม่ทับซ้อนกัน): ในวันที่ 15 / เม.ย. อาจารย์อาจมีช่องเวลา 10:00, 11:00, 12:00 และ 16:00 . บุคคลจะได้รับหลังจากเลือกเวลา / ช่องของครูที่เฉพาะเจาะจง
ช่วงเวลา / ช่วงเวลา : วันที่ 15 / เม.ย. ครูคนอื่นอาจทำงานได้ตั้งแต่ 10:00 น. ถึง 12:00 น. และจากเวลา 14:00 น. ถึง 18:00 น. บุคคลที่มาถึงตามคำสั่งของการมาถึงดังนั้นหากครูทำงานตั้งแต่เวลา 10:00 น. ถึง 12:00 น. ทุกคนที่มาถึงในช่วงเวลานี้จะเข้าร่วมตามลำดับของการมาถึง (คิวท้องถิ่น)
เนื่องจากฉันต้องส่งคืนอาจารย์ที่มีอยู่ทั้งหมดในการค้นหาฉันจึงต้องการบันทึกช่องทั้งหมดในตารางเดียวกันตามลำดับของช่วงการมาถึง วิธีนี้ฉันสามารถสั่งซื้อโดย 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.10 มิลลิวินาทีแบบสอบถามที่สอง 0.08 มิลลิวินาทีและยูเนี่ยนทั้งหมดเฉลี่ย 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;
คำถาม
มีวิธีเพิ่มประสิทธิภาพยูเนี่ยนดังนั้นฉันสามารถได้รับการตอบสนองที่เหมาะสมของสูงสุด ~ 20ms หรือแม้แต่กลับช่วงตาม + รายชั่วโมงตามเพียงหนึ่งแบบสอบถาม (ด้วย 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
มันช่วยฉันได้ 100ms แล้ว! โดยเฉลี่ย 200ms