मेरे पास एक तालिका है जो शिक्षकों के लिए उपलब्ध नियुक्तियों को संग्रहीत करती है, दो प्रकार के सम्मिलन की अनुमति देती है:
प्रति घंटा आधारित : प्रति शिक्षक प्रति दिन असीमित स्लॉट्स जोड़ने की पूर्ण स्वतंत्रता के साथ (जब तक स्लॉट ओवरलैप नहीं होते हैं): 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)।
के लिए प्रति घंटा के आधार मैं हर शिक्षक के लिए पहली निकटतम उपलब्ध दिन के लिए सभी उपलब्ध स्लॉट्स दिखाने के लिए (किसी विशेष दिन के सभी समय स्लॉट दिखाने के लिए और एक ही शिक्षक के लिए और अधिक से अधिक एक दिन नहीं दिखा सकते हैं)। (मुझे मैटेडगॉड की मदद से क्वेरी मिली )।
के लिए आधारित रेंज (order_of_arrival = 1), मैं निकटतम उपलब्ध रेंज, प्रति शिक्षक सिर्फ एक समय दिखाने के लिए।
पहली क्वेरी लगभग ०.१० एमएस, दूसरी क्वेरी ०.० and एमएस और यूनिअन सभी में ३०० मी की औसत चलती है।
(
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, आदि के साथ) में आधारित है?
एसक्यूएल फिडेल: 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 बचा लिया! अभी भी औसतन 200 मी।