私は弁護士予約システムを開発しています。このシステムでは、特定の日の特定の時間(次の弁護士の対応可能日)に予約を入れることができます。
弁護士向けのZocDocだとしましょう。同じ構造で、時間に基づいて予定があります:http: //goo.gl/djUZb
MySQLとPHPを使用しています。
テーブルスキーマ:
CREATE TABLE `laywer_appointments` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`lawyer_id` INT unsigned,
`day_of_week` tinyint(3) unsigned DEFAULT '1',
`slot_date` date DEFAULT NULL,
`slot_time` time DEFAULT NULL,
`status` tinyint(4) NOT NULL DEFAULT '0',
`client_id` int(11) DEFAULT NULL, -- client_id = NULL means free slot
);
ポイント1)
各弁護士には、曜日に基づいたデフォルトのタイムスロットがあります(ステータス= 0は利用可能であることを意味します)。デフォルトのスロットを挿入するとき、日付は指定せず、day_of_weekだけを指定します。データ例:
+-----------+-------------+-----------+-----------+
| lawyer_id | day_of_week | slot_time | status |
+-----------+-------------+-----------+-----------+
| 1 | 1 | 08:00 | 0 |
| 1 | 1 | 08:30 | 0 |
| 1 | 1 | 09:00 | 0 |
| 1 | 1 | 10:30 | 0 |
| 1 | 4 | 14:30 | 0 |
| 1 | 4 | 16:40 | 0 |
| 2 | 1 | 10:20 | 0 |
| 2 | 1 | 14:00 | 0 |
| 2 | 3 | 15:50 | 0 |
+-----------+-------------+-----------+-----------+
ポイント2)
弁護士は、特定の日にタイムスロットを追加でき(この日がデフォルトのスロットとは異なる曜日であっても) 、特定の日のデフォルトのスロットの1つをロック(ステータス= -1)することもできます(つまり、彼は会議中または彼は病気です):
+-----------+-------------+-----------+-----------+-----------+
| lawyer_id | day_of_week | slot_time | slot_date | status |
+-----------+-------------+-----------+-----------+-----------+
| 1 | 1 | 16:00 | 12/03/13 | 0 |
| 1 | 6 | 11:00 | 26/04/13 | 0 |
| 1 | 6 | 12:00 | 26/04/13 | 0 |
| 2 | 1 | 10:00 | 01/01/13 | -1 |
+-----------+-------------+-----------+-----------+-----------+
ポイント3)
その後、予約があります。この場合、slot_dateとclient_idを入力します。
+-----------+-------------+-----------+-----------+-----------+
| lawyer_id | day_of_week | slot_time | slot_date | client_id |
+-----------+-------------+-----------+-----------+-----------+
| 1 | 1 | 10:30 | 12/03/13 | 10 |
+-----------+-------------+-----------+-----------+-----------+
例として、上記の予約で、同じ日の6:30(12/03/13)であると仮定すると、印刷する必要のある空きスロットは次のとおりです。
8:00 - default slot
8:30 - default slot
9:00 - default slot
16:00 - Specific slot inserted in point 2 for 12/03/13
問題:
次の利用可能な日付と関連する空き時間(デフォルトのもの、特定のものからロックされたものと予約されたものを差し引いたもの)を返さなければなりません。「月曜日からの帰りの時間、10/10/13」とは言えません。
検索結果ページに、すべての弁護士とそれぞれの弁護士の空き時間表を一覧表示します。つまり、検索が行われるたびに、各弁護士は異なるタイムテーブルを持つことになります。
「SELECTtimeFROM[bunch of joins] WHERE date=today」と単純に言うことはできません。
ロックされている(status = -1)または予約されている(client_idがnullではない)スロットを無視するこのクエリが付属していますが、もちろん、利用可能な時間(または今日から)で最も近い日の空き時間を返しません:
SELECT p.day_of_week, p.slot_date, p.slot_time
FROM laywer_appointments p
WHERE p.client_id IS NULL AND p.status = 0
AND p.slot_time NOT IN (
SELECT s.slot_time FROM laywer_appointments s
WHERE (s.slot_date IS NOT NULL AND s.client_id IS NOT NULL
OR s.status = -1) AND s.day_of_week = p.day_of_week
)
GROUP BY p.day_of_week, p.slot_date, p.slot_time
ORDER BY p.day_of_week ASC, p.slot_time ASC;
別の問題:今日がday_of_week = 5であるが、特定の弁護士が次に利用できるday_of_weekが2である場合、どうすればそれを照会できますか?
次に近い利用可能なday_of_weekを返し、すべての日ではなく、この日からの時間を返すように集計するにはどうすればよいですか?
1つの可能な解決策
私が持ってきたものの1つは、1つではなく3つのテーブルを作成することでした。
- default_slots:3列:lawyer_id、day_of_week、time
- スロット:laywer_id、day_of_week、time、date、status
- アポイントメント:予約されたアポイントメントに関するすべての情報
次に、実際の日付から1年までの毎日のすべての空き時間枠を、すべての弁護士のスロットテーブルに保存します。(default_slotsから取得したタイムスロット)。
+-----------+-------------+-----------+-----------+-----------+
| lawyer_id | day_of_week | slot_time | slot_date | status |
+-----------+-------------+-----------+-----------+-----------+
| 1 | 1 | 16:00 | 12/03/13 | 0 |
| 1 | 1 | 16:00 | 12/03/13 | 0 |
| 1 | 2 | 08:00 | 13/03/13 | 0 |
| 1 | 2 | 09:00 | 13/03/13 | 0 |
... next week
| 1 | 1 | 16:00 | 19/03/13 | 0 |
| 1 | 1 | 16:00 | 19/03/13 | 0 |
| 1 | 2 | 08:00 | 20/03/13 | 0 |
| 1 | 2 | 09:00 | 20/03/13 | 0 |
... up to an year
| 1 | 1 | 16:00 | 20/03/14 | 0 |
| 1 | 1 | 16:00 | 20/03/14 | 0 |
| 1 | 2 | 08:00 | 21/03/14 | 0 |
| 1 | 2 | 09:00 | 21/03/14 | 0 |
+-----------+-------------+-----------+-----------+-----------+
また、毎週実行されるcronジョブをいくつか実行して、テーブルスロットにさらに1週間の空きスロットレコードを追加し、過去のレコードを削除してテーブルサイズと未使用データを削減します。
弁護士は、時間を直接スロットに固定したり、特定の時間を追加したりすることもできます(ポイント2)。
リストの場合、すべての日付のすべての時間に行があるため、今日と同じかそれ以上の日付のスロットを空き時間で取得する必要があります。
このソリューションへの影響:1)初日は2500人の弁護士がいます(2か月目は約6000人)。8つの可能なスロット/日X20日間の作業/月X12か月=弁護士あたり1920スロットのレコードを想定しています。
2500 laywersx1920レコード=初日で480万レコード。(2か月目は約12M)
これらのレコードは常に更新、挿入、削除されます。スロットテーブルにはいくつかのインデックスがあるため、1200万以上のレコードといくつかのインデックスを持つテーブルで書き込み操作が常に行われることは想像できません。毎秒更新されるインデックスは、私には賢く見えません。
合理的でスケーラブルなソリューションを実際に提供することはできません。1つのテーブルを使用した私のソリューションは機能しましたが、それを照会する方法をまったく考えることができません。また、非正規化されたスロットテーブルは巨大になりますが、一定の書き込み操作が必要になります。
任意のヒント?