web-dev-qa-db-ja.com

毎日のイベントのデータベースを構築する方法は?

ユーザーが特定の日に出席を記録したかどうかを記録するデータを保存しています。重要でない日(休日、週末)があるため、それらも保存されます。

2つの要件は次のとおりです。

  1. ログの数と失われたログの数をすばやく計算できます。
  2. この構造は、新しいユーザーが追加されるたびに呼び出すことができます。

今のところ、データの保存方法について2つのオプションに直面しているようです。それぞれに独自の利点と欠点があります。

オプション1:2つのテーブル

テーブルcalendar-カウントされない日数を追跡します

date       | log |
-----------+-----|
2019-01-10 | DNL | // "Do Not Log" - holiday etc.
2019-01-12 | NB  | // "Non-business day"
2019-01-13 | NB  |

テーブルlogs-成功した出席ログを追跡します

user_id | date       |
--------+------------|
      1 | 2019-01-08 |
      1 | 2019-01-09 |
      2 | 2019-01-09 |

// It's implied that user #2 missed their log on Jan. 8

利点:

  • データは効率的に保存されます。
  • ユーザーログと非カウント日を集計するのは簡単です。

課題:

  • 逃した日数を知ることは明らかではありません。

オプション2:1つのテーブル(私が試したこと)

テーブルcalendar-カウントするログとカウントしない日を追跡します

date       | user_id | log  |
2018-01-09 |       1 |    1 | // Counted, logged
2019-01-10 |       1 |  DNL | // Not counted
2019-01-11 |       1 |   NB | // Not counted
2019-01-09 |       2 | NULL | // Counted, missed log

利点:

  • 失敗した日数と記録された日数の集計は、取るに足らないものです(全体のパーセンテージの計算に使用されます)。カレンダーの日数は明確です。

課題:

  • カレンダーに新しいエントリを追加するのは、次のような場合には注意が必要です。
    • カレンダーの長さが長くなります。
    • 新しいユーザーが追加されます。
  • テーブルにギャップがあります(どこでもlog == NULL)。走査はオプション1より遅くなります。

私の質問はこれです:オプション1を使用して、何らかの理由で失われたログの数をエンコードする方法はありますか、または両方の要件を満たすデータを格納する他の方法はありますか?オプション2を試してみましたが、スケーリングが非常に困難になりました。アドバイスを事前にありがとう。

2
cameraguy258

両方のデザインを台無しにするいくつかのケースを以下に示します:教師は病気になります。労働組合はストライキを行っている。サーバーがダウンします。雪の日が起こります。

クラスは、シラバスの内容に関係なく発生します。したがって、未来がどうなるかを知っているふりをするのではなく、発生したイベントを記録するだけです。

イベント:

  • インストラクターは今日が授業日であることを宣言します
  • 学生は本日出席を宣言します

欠席=クラス日-出席

利点:設計では、紛らわしい誤解を招く説明のないヌルを使用する必要がありません。

1
candied_orange

必要なのはこれに沿ったものです:

Calendar {
    DateId int not null;
    Date datetime not null;
}

DoLogDay {
    DateId int not null (foreign key to DateId column in Calendar);
    LogDay bit not null;
}

UserLog {
    DateId int not null (foreign key to DateId column in Calendar);
    UserId int not null;
}

DateIdを導入する理由は、実際の日/月/年がスキーマで一度だけ指定されるためです。ユーザーの出席状況を記録するにはDateIdを調べる必要がありますが、アプリの起動時にDateIdと日付のマッピングをフェッチしてキャッシュできると思います。

また、DateIdsの使用は、DBのコード内の日付で発生する可能性のある奇妙さを取り除いたため、計算を行う必要があるときにインデックスに適した列があることを意味します(奇妙な動作があるとは言っていませんが、しかし、私は奇妙な問題がintよりも日付の可能性が高いと予想します)。

インデックスを使用すると、挿入が遅くなります(テーブルを更新するだけでなく、インデックスを更新する必要があります)が、この挿入時間の増加は問題にならない可能性があります。初期データベースを構築するときにインデックスを追加する必要はありません。確かに、インデックスの有無にかかわらずパフォーマンステストを行うことができます。インデックスビットをDateIdの「ボーナス」と考えてください。 DateIdは、「主要な」目的としての冗長な日付を取り除きます。

0
Dev243