教師が利用できる予定を保存するテーブルがあり、2種類の挿入が可能です。
時間単位:教師ごとに1日あたり無制限のスロットを追加する自由(スロットがオーバーラップしない限り):4月15日、教師は10:00、11:00、12:00、16:00にスロットを持つことができます。特定の教師の時間/スロットを選択すると、担当者が対応します。
時間帯/範囲:4月15日/ 4月に別の教師が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、およびスロットが使用可能かどうか(status = 0)でフィルターする必要があります。
時間ベースの場合、すべての先生の最初の最も近い利用可能な日にすべての利用可能なスロットを表示する必要があります(特定の日のすべてのタイムスロットを表示し、同じ先生に複数の日を表示することはできません)。(私はmattedgodの助けを借りてクエリを取得しました)。
以下のために基づいて、範囲(order_of_arrival = 1)、私は最も近い利用可能な範囲、教員ごとに1つの時間を表示する必要があります。
最初のクエリは約0.10ミリ秒で個別に実行され、2番目のクエリは0.08ミリ秒、UNION ALLは平均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;
質問
UNIONを最適化する方法はありますか?たった1つのクエリ(IFなど)で、最大20msまでの適切な応答を得ることができます。
SQLフィドル: 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。