3

市内のさまざまなチームが定期的に参加するスポーツ合宿があります。1 日あたり 2 時間 (午前 9 時から 11 時) のセッションがあり、時間枠はチームによって異なる場合があります。誰が合宿に参加したかを日常的に把握したいと考えています。

出席者をキャプチャするために、次のモデルに到達しました。(id、user_id、日付、現在)。ユーザーが毎日 (たとえば、1 か月に 30 日) キャンプに参加すると仮定すると、データベースに多数のレコードが表示されます。

ユーザーがキャンプに参加した日数を知ることのみに関心があると仮定すると、特定のユーザーの有無をマークするより良い方法はありますか (おそらく、1 か月の行を 1 つだけ作成し、個々の日をすべて次のようにマークします)。 (P,P,P,A, ...,A,P). P = 存在、A = 不在のようなもの

4

4 に答える 4

3

最適化する内容を説明せずに、質問のタイトルに「最適化」という言葉を使用します。

クエリのパフォーマンスについて話しているのであれば、問題はありません。保持できるレコードの数は、毎日のセッション数によって決まります (特定のセッションに参加できるのは 1 つのチームのみであるため)。1 日に 10 セッションを実行すると、1 か月あたり 300 レコードになります。1 日に 100 セッションを実行すると、1 か月に 3,000 レコードになります。これらは大量のデータではありません。したがって、存在しないパフォーマンスの問題を回避するためにデータベースの設計を歪めることで、悪い決定を下しています。

コメントの 1 つでスプレッドシートについて言及しました。それは悪いデザインではありません。一番上の行にはセッションがあり、その下にはチームがあり、セルはチームがセッションに参加したかどうかを示しています。これらは、SESSIONS、TEAMS、および交差テーブル TEAM_SESSIONS の 3 つのデータベース テーブルにマップされます。チームがセッションに参加した場合、TEAM_SESSIONS のレコードのみが必要です。

概念実証として、私は Oracle で 3 つのテーブルを作成しました。

SQL> desc teams
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 ID                                        NOT NULL NUMBER
 NAME                                               VARCHAR2(20 CHAR)

SQL> desc sessions
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 ID                                        NOT NULL NUMBER
 SSN_DAY                                            DATE
 SSN_START                                          NUMBER(4,2)
 SSN_END                                            NUMBER(4,2)

SQL> desc team_sessions
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 TEAM_ID                                   NOT NULL NUMBER
 SESSION_ID                                NOT NULL NUMBER

SQL>

Oracle 11g で導入された PIVOT 関数を使用すると、簡単にマトリックスを作成できます (DBMS の種類が異なれば、これにアプローチする方法も異なります)。ご覧のとおり、今日は 3 つのチームがセッションを予約しており、誰もランチタイムにトレーニングをしたくありません。Bec United はマスタードのように熱心です (またはトレーニングが必要です)。

SQL> select * from (
  2      select t.name as team_name
  3             , trim(to_char(s.ssn_start))||'-'||trim(to_char(s.ssn_end)) as ssn
  4             , case when ts.team_id is not null then 1 else 0 end as present
  5      from   sessions s
  6             cross join teams t
  7             left outer join team_sessions ts
  8                  on (ts.team_id = t.id
  9                      and ts.session_id = s.id )
 10      where s.ssn_day = trunc(sysdate)
 11      )
 12  pivot
 13      ( sum (present)
 14        for ssn in ( '9-11', '11-13', '13-15', '15-17', '17-19')
 15      )
 16  order by team_name
 17  /

TEAM_NAME                '9-11'    '11-13'    '13-15'    '15-17'    '17-19'
-------------------- ---------- ---------- ---------- ---------- ----------
Balham Blazers                0          1          0          0          0
Bec United                    1          0          0          0          1
Dinamo Tooting                0          0          0          0          0
Melchester Rovers             0          0          0          1          0

SQL>

いずれにせよ、このデータ モデルの利点は、柔軟であることです。チームの出席頻度、出席時刻、出席曜日、常に予約されているセッション、ほとんど予約されていないセッションなどを数えることができます。また、データの管理も簡単です。特に、2 つのテーブルよりも 3 つのテーブル ソリューションの利点は、ダブルブッキングや非標準または重複する時間枠を簡単に防ぐことができることです。

ノーマライゼーションは、罪のない人をだますために使用する単なる月の言葉ではなく、実際的なメリットを提供します。少なくとも BCNF まで下げることが最善の考えではないシナリオはほとんどありません。

于 2010-07-07T12:39:38.343 に答える
2

なぜそんなことをするのかを自問する必要があります。

いくつかの可能性がありますが、データベース スキーマが完全に正規化されていない可能性があります。

まず第一に、何を達成したいのか、その理由は何ですか?

いくつかの可能性:

  • 一部の DBMS は、ユーザー定義型を作成する機能を提供します。
  • ビット単位のアプローチを使用できます (mysql では、SET データ型を使用するのが最も簡単な方法です) 。

しかし、繰り返しになりますが、現在の問題は何ですか。誰かが存在した日数を知ることは、適切なテーブルを結合し、count 関数で集計することに他なりません。

于 2010-07-07T09:15:46.203 に答える
1
AttMst
  id | date

AttDet
  attdetid | id | userid

このように、AttMst に日を保存する必要があり、その日の現在のユーザーは AttDet に保存されます。

于 2010-07-07T09:18:31.610 に答える
0

IMHO、連結された文字がたくさんあるユーザーごとに毎月 1 つの行を持つことは、特に毎回その文字列を分割する必要がある場合は、その上に 1 つの文字を持つ多くの行を持つことよりも優れているとは言えません。別のアプリケーションでデータを表示したい。

ユーザーがキャンプに参加した日数を把握したいだけなら、専用のテーブルを作成してみませんか? ユーザーの出席を記録するたびに、ユーザーが出席した日数を増やしてそのテーブルを更新するだけで済みます。そのため、この値はオンザフライで計算されず、パフォーマンスの問題は発生しません。

したがって、私のアドバイスは次の 2 つの表で構成されます。

id | user_id | date | present

user_id | month | attendance

システムのパフォーマンスを向上させるために、user_id フィールドにもいくつかのインデックスが必要です。

乾杯

于 2010-07-07T09:03:04.517 に答える