İki tür eklemeye izin veren öğretmenler için kullanılabilir randevuları depolayan bir masam var:
Saatlik tabanlı : öğretmen başına günlük sınırsız alan ekleme özgürlüğüyle . Bir kişiye belirli bir öğretmen zamanı / alanı seçildikten sonra servis yapılır.
Süre / aralık : 15 / Nisan'da başka bir öğretmen 10:00 ila 12:00 ve ardından 14:00 ila 18:00 saatleri arasında çalışabilir. Bir kişiye varış sırasına göre hizmet verilir, bu nedenle bir öğretmen 10:00 ile 12:00 arasında çalışırsa, bu dönemde gelen tüm kişilere varış sırası (yerel kuyruk) katılacaktır.
Mevcut tüm öğretmenleri bir aramada geri göndermem gerektiğinden, tüm alanların varış aralıklarının sırası ile aynı tabloya kaydedilmesi gerekir. Bu şekilde ASC'den date_from'a göre sipariş verebilirim ve arama sonuçlarında ilk kullanılabilir alanları gösterir.
Mevcut tablo yapısı
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;
Arama sorgusu
Filtre uygulamak gerekir: gerçek datetime, city_id, konu_kimliği ve bir yuva varsa (status = 0).
İçin Saatlik dayalı her öğretmen için ilk yakındaki uygun gün için mevcut tüm yuvaları göstermek zorunda (belirli bir günde tüm zaman aralıkları göstermek ve aynı öğretmen için bir günden fazla gösteremez). (Sorguyu mattedgod yardımı ile aldım ).
İçin bazlı aralık (order_of_arrival = 1), ben en yakındaki uygun aralık, öğretmen başına sadece bir kez göstermek zorundayız.
İlk sorgu tek başına yaklaşık 0.10 ms, ikinci sorgu 0.08 ms ve UNION ALL ortalama 300ms'de çalışır.
(
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;
Soru
BİRLİĞİ optimize etmenin bir yolu var mı, bu yüzden maksimum bir ~ 20 ms makul bir yanıt alabilir veya hatta sadece bir sorguya dayalı (saatlik bir IF, vb.) + Dönüş aralığı tabanlı?
SQL Fiddle: http://www.sqlfiddle.com/#!2/59420/1/0
DÜZENLE:
Ben sadece tarih depolanmış bir alan "only_date_from" oluşturarak bazı denormalization denedim, bu yüzden bu değiştirebilir ...
DATE(MIN(date_from)) as closestDay / DATE(teacher_slots.date_from) = closestDay
... buna
MIN(only_date_from) as closestDay / teacher_slots.only_date_from = closestDay
Beni zaten 100ms kurtardı! Hala ortalama 200 ms.