Saya memiliki tabel yang menyimpan janji temu untuk guru, memungkinkan dua jenis sisipan:
Berbasis per jam : dengan kebebasan penuh untuk menambahkan slot tanpa batas per hari per guru (selama slot tidak tumpang tindih): pada 15 / April seorang guru mungkin memiliki slot pada 10:00, 11:00, 12:00 dan 16:00 . Seseorang dilayani setelah memilih waktu / slot guru tertentu.
Periode / rentang waktu : pada 15 / Apr guru lain mungkin bekerja dari 10:00 hingga 12:00 dan kemudian dari 14:00 hingga 18:00. Seseorang dilayani berdasarkan urutan kedatangan, jadi jika seorang guru bekerja dari pukul 10:00 hingga 12:00, semua orang yang tiba pada periode ini akan dihadiri oleh urutan kedatangan (antrian lokal).
Karena saya harus mengembalikan semua guru yang tersedia dalam pencarian, saya perlu semua slot disimpan dalam tabel yang sama dengan urutan kedatangan. Dengan cara ini saya dapat memesan berdasarkan date_from ASC, menunjukkan slot yang tersedia pertama terlebih dahulu pada hasil pencarian.
Struktur tabel saat ini
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;
Permintaan pencarian
Saya perlu memfilter menurut: datetime aktual, city_id, subject_id dan jika slot tersedia (status = 0).
Untuk setiap jam saya harus menunjukkan semua slot yang tersedia untuk hari terdekat pertama yang tersedia untuk setiap guru (tampilkan semua slot waktu pada hari tertentu dan tidak dapat menampilkan lebih dari satu hari untuk guru yang sama). (Saya mendapat permintaan dengan bantuan dari mattedgod ).
Untuk rentang berdasarkan (order_of_arrival = 1), saya harus menunjukkan rentang terdekat yang tersedia, hanya satu kali per guru.
Permintaan pertama berjalan secara individual di sekitar 0,10 ms, permintaan kedua 0,08 ms dan UNION ALL rata-rata 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;
Pertanyaan
Apakah ada cara untuk mengoptimalkan UNION, jadi saya bisa mendapatkan respons yang masuk akal dari maksimum ~ 20 ms atau bahkan rentang pengembalian + jam berdasarkan hanya dalam satu permintaan (dengan IF, dll)?
SQL Fiddle: http://www.sqlfiddle.com/#!2/59420/1/0
EDIT:
Saya mencoba beberapa denormalisasi dengan membuat bidang "only_date_from" di mana saya hanya menyimpan tanggalnya, jadi saya bisa mengubah ini ...
DATE(MIN(date_from)) as closestDay / DATE(teacher_slots.date_from) = closestDay
... untuk ini
MIN(only_date_from) as closestDay / teacher_slots.only_date_from = closestDay
Itu sudah menyelamatkan saya 100 ms! Masih rata-rata 200 ms.