Ich habe eine Tabelle, in der verfügbare Termine für Lehrer gespeichert sind und zwei Arten von Einfügungen möglich sind:
Stundenbasiert : mit der völligen Freiheit, unbegrenzte Zeitnischen pro Tag und Lehrer hinzuzufügen (solange sich die Zeitnischen nicht überschneiden): Am 15. April kann ein Lehrer Zeitnischen um 10:00, 11:00, 12:00 und 16:00 Uhr haben . Eine Person wird bedient, nachdem eine bestimmte Lehrerzeit / ein bestimmtes Zeitfenster ausgewählt wurde.
Zeitraum / Bereich : Am 15. April kann ein anderer Lehrer von 10:00 bis 12:00 Uhr und dann von 14:00 bis 18:00 Uhr arbeiten. Eine Person wird in der Reihenfolge ihrer Ankunft bedient. Wenn also ein Lehrer von 10:00 bis 12:00 Uhr arbeitet, werden alle Personen, die in diesem Zeitraum ankommen, in der Reihenfolge ihrer Ankunft (lokale Warteschlange) betreut.
Da ich bei einer Suche alle verfügbaren Lehrer zurückgeben muss, müssen alle Slots in derselben Tabelle wie die Reihenfolge der Ankunftsbereiche gespeichert werden. Auf diese Weise kann ich nach Datum_von ASC bestellen und die ersten verfügbaren Slots zuerst in den Suchergebnissen anzeigen.
Aktuelle Tabellenstruktur
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;
Suchanfrage
Ich muss filtern nach: Istdatum / Uhrzeit, Stadt-ID, Betreff-ID und ob ein Steckplatz verfügbar ist (Status = 0).
Für stündlich muss ich für jeden Lehrer alle verfügbaren Slots für den nächstgelegenen verfügbaren Tag anzeigen (alle Zeitfenster eines bestimmten Tages anzeigen und kann nicht mehr als einen Tag für denselben Lehrer anzeigen). (Ich habe die Anfrage mit Hilfe von mattedgod bekommen ).
Für Bereich basierte (order_of_arrival = 1), ich habe den am nächsten verfügbaren Bereich zeigen, nur einmal pro Lehrer.
Die erste Abfrage wird einzeln in ca. 0,10 ms ausgeführt, die zweite Abfrage 0,08 ms und die UNION ALL durchschnittlich 300 ms.
(
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;
Frage
Gibt es eine Möglichkeit, die UNION zu optimieren, damit ich in nur einer Abfrage (mit einer IF usw.) eine vernünftige Antwort von maximal ~ 20 ms oder sogar einen Rückgabebereich + stündlich erhalten kann?
SQL Fiddle: http://www.sqlfiddle.com/#!2/59420/1/0
BEARBEITEN:
Ich habe eine Denormalisierung versucht, indem ich ein Feld "only_date_from" erstellt habe, in dem ich nur das Datum gespeichert habe, damit ich dies ändern kann ...
DATE(MIN(date_from)) as closestDay / DATE(teacher_slots.date_from) = closestDay
... dazu
MIN(only_date_from) as closestDay / teacher_slots.only_date_from = closestDay
Es hat mich schon 100ms gerettet! Im Durchschnitt immer noch 200 ms.