ここに私が働いているデータベースに存在するいくつかのテーブルの例があります。データは実際には学校に関するものではありませんが、構造は同じです。
4つのテーブルがあります。
** School **
School Id, School Name
** ClubType **
ClubType Id, ClubType Name
** Club **
Club Id, School Id, ClubType Id
** Student **
Student Id, Name, Club Id
(実際のデータは実際には学校のクラブに関するものではないため)Clubテーブルには追加の列が含まれないことを知っている
結合を回避するためにクラブテーブルを削除した、明らかにより良い設計は次のようになると思います。
** School **
School Id, School Name
** ClubType **
ClubType Id, ClubType Name
** Student **
Student Id, Name, School Id, ClubType Id
編集:各クラブIDには1つのタイプしか指定できないこともわかっています。 ClubからClubTypeへの関係は1対1です。
私の質問は、最初の例は、データベースの正規化のいくつかの既知のルールまたは他のいくつかの数学的原理に違反していますか?それとも、デザインが悪い場合だけですか?
提案されたソリューションに変更すると、データベースから情報が失われます。既存のソリューションでは、特定の学校に実際にクラブにいる人に関係なく、特定の学校にどのクラブが存在できるかが示されています。提案されたソリューションでは、クラブが誕生する前に(つまり、行がデータベースに書き込まれる前に)誰かがクラブに参加する必要があります。
実用的な含意として、サインアップシートを考えてください。学期が始まる前日です。校長は、生徒が参加できるように、各クラブの掲示板にサインアップシートを必要としています。すべての種類のクラブのシートを印刷して、学生が決して存在しないクラブに参加できるようにするのは無駄ですこの学校では。今日、学期が始まる前に学生がいないため、提案されたソリューションは機能しません。ただし、既存のソリューションでは、校長はたとえばサッカークラブを提供できますが、水球クラブは提供できません。
学校やクラブの類推を実際の状況の代用として使用していることを承知しており、私が言うすべてを実際の問題に翻訳する必要があり、これから行うコメントは適用されない場合があります。それがアナロジーに支払う代償です。実際の「学校」が常にすべての「クラブタイプ」から選択できる場合、提案されたソリューションは適切です。
それとも、デザインが悪い場合だけですか?
デザイン不良ではありません。それも良いデザインではありません。それは、いくつかのアフォーダンスを実装するが、他のものを排除する設計です。それは私たちがアクセスできない理由のために書かれました。それは、当時利用可能な知識で書かれました。おそらく、非常に多くのテストとアクティブな運用環境での使用に合格しています。
今、世界はそれ以来進んでいるのかもしれません。ビジネスルールが変更された可能性があります。実装チームの理解が向上した可能性があります。その設計には、データが与えられたワークロードのハードウェアでは許容できないパフォーマンス特性がある場合があります。その設計を変更することが適切な場合があります。
正規化は、非キー列が単一のテーブル内のキー列にどのように依存するかについてです。これは、スキーマを変更して、実際の単一の値を変更すると、データベース内の単一の行の単一の列が更新される方法を示しています。現実の問題からシナリオを実装することについては言うまでもありません。
現在の生徒の表は、「クラブのメンバーとしての人物」を意味していると理解しています。そのため、主キーは{student id、club id}になります。現在の実装では、名前はクラブIDではなく学生IDにのみ依存するため、テーブルは正規化されていません。正規化されたソリューションは、テーブルStudentのセマンティクスを "A person"(列生徒ID、名前)に変更し、列{生徒ID、クラブID}を持つ新しいテーブルClubMemberを作成することです。
ClubからClubTypeへの関係は1対1です。
疑わしい。 ClubTypeの可能な値は何ですか? 「サッカー」とか「ヨガ」とか?たくさんの学校がサッカー部を作りたいと思っています。たぶん
Each Club is-this-schools exactly one ClubType
Each ClubType is-offered-in zero or more Club
ERDとして:
ClubType --< Club >-- School
最初の例は、データベースの正規化のいくつかの既知のルールまたは他のいくつかの数学的原理に違反していますか?それとも、デザインが悪い場合だけですか?
どちらでもない。正規化または優れた設計の明らかな欠陥はありません。
次のような命題をうまくモデル化します。
そのモデルの唯一の奇妙なことは、学生は1つのクラブのメンバーにしかなり得ないということです。それは理にかなっています、それは実際の学校にとっては珍しいルールになるでしょう。
私の観点からすると、あなたの生徒のテーブルは「奇妙」です...ほとんどの学校は生徒を1つのクラブに制限しません。
生徒用のテーブルをできるだけ「短く」します
**学生**
学生ID、名前
通常、1つの学校のデータベース全体が存在するため、列の学校IDでさえ疑問があります。そのため、学校IDは気づかれていません。しかし、それはあなたが例を使用しようとすることから来るかもしれません-私の他のフォーラムでは、私たちは通常あなたが陥った「罠」を避けるためにデータを単に隠す/匿名化する本当の「例」を使用するためのヒントを与えます。
あなたの目標は結合を減らすことですが、これらは効率的なデータベース設計(リレーショナルデータベースモデルの「関係」)の真の鍵です。
だから私は少なくともテーブルを持っているだろう
**学生クラブのマッピング**
学生ID、クラブID
ここで、両方の列の組み合わせは一意でキーです。これにより、学生は言語とスポーツクラブの両方に参加することができます。そのような学生がいると信じてください^^
編集:あなたの元のレイアウトでは、テーブルのレイアウトにそのように書かれているため、学生を1クラブに制限しています
**学生**学生ID、名前、クラブID
このレイアウトでは通常、学生ID(キーとして)が一意である必要があります。したがって、1人の学生= 1行= 1クラブその他すべてが非常に悪いデータベース設計です(クラブID列にいくつかのクラブIDをリストすると、おそらくカンマで区切ると構築時に悪夢になります)たとえば、クラブのリストから学生名簿を選択します)
2番目の設計では、DBアプリケーションによっては、異なる時点で存在する2つのクラブである可能性がある(同じ学校の同じタイプの複数のクラブをサポートしていません(当校では、学生ジャーナルは存在しなくなったため、再開しました)。
これに関連して、あなたが表現することができないかぎこちなくなることがたくさんあります:
では、質問:どの生徒がこの生徒が所属していたクラブを監督していたのでしょうか。 2番目の定式化では不可能です。
つまり、2つのデザインは異なる関係をカバーしていますが、(クラブの種類、学校)と(クラブ)の1対1が与えられれば、2番目のデザインは問題ないはずです。
提案されたソリューション間の違いは、正規化とは関係のないAFAIUです。
この特定のデータベース構造で他の問題が見られますが、OPの質問に直接回答するには、
いいえ、SchoolやClubTypeなどのルックアップテーブルを使用しても、正規化ルールに違反しません。これは、ID値を中心にテーブルを作成し、ルックアップテーブルにテキスト値を簡単に読み取れるようにするための、非常に標準的な方法です。
データベース構造で私が目にする問題に対処するために、
この例のClubテーブルには、学校IDフィールドはなく、名前フィールドも必要です。これは、クラブタイプ名とクラブ名がクラブの2つの異なる機能になる可能性があるためです。さらに、同じクラブが複数の学校に存在する可能性があります。
また、学生は複数のクラブに所属することができるため、学生にはクラブIDフィールドを含めないでください。
最後に、このデータベースには実際には、クラブ:学校と学生:クラブの多:多の関係を処理するために、さらに2つのテーブルが必要です。
これは実際のデータベースではないので、実際の問題がどのようなものであるかを推測するだけにとどめます。専有情報を提供したくないのではないかと思いますが、本当の問題は匿名化できませんでしたか?とにかく、議論のために、あなたが与える問題が本当の問題であるかのようにこれを議論します。
最初のデータベース設計は理にかなっており、ほとんどが適切に編成および正規化されています。
学校はいくつでも持つことができます。これは、3つの小学校、2つの中学校、高校のように、地区に複数の学校がある場合に意味があります。
多くの種類のクラブがあります。クラブの種類はわかりませんが、「スポーツ」対「アカデミック」対「カルチュラル」のどちらかだと思います。
クラブタイプ内には多くのクラブが存在する可能性があります。スポーツクラブのように、サッカー、野球、ホッケーが含まれる場合があります。
学校にはクラブが存在します。高校にはフットボールクラブがあるかもしれませんが、小学校にはありません。
学生は、1つ以上のクラブのメンバーになることができます。または、学生は1つのクラブの会員になることができますか?学生が複数のクラブに所属できる場合、学生の名前はすべてのクラブで繰り返されます。これは冗長なデータであり、誤りです。 Studentには、student_idと名前の別のテーブルと、student_idとclub_idのクラブメンバーシップが必要です。万が一、学生が1つのクラブに所属することのみが許可されている場合は、指定されたデザインが正しいことになります。
あなたが提案された代替案は多くの問題を引き起こします。
クラブタイプ内の異なるクラブを区別できません。各タイプのクラブが1つしかない場合は、大丈夫です。別のクラブタイプとクラブテーブルを用意する必要はなく、2つを組み合わせることができます。ただし、1つのタイプ内に複数のクラブが存在する可能性がある場合、この情報は破棄されています。
「クラブタイプ」と「クラブ」が同じものであると仮定すると、各学校にどのクラブ/クラブタイプが存在するかを言う機能がなくなりました。たとえば、高校にはチェスクラブがあるとは言えませんが、中学校にはありません。
最初のデザインと同様に、学生が複数のクラブ/クラブタイプに所属できる場合、学生の名前と学校IDはすべてのクラブで繰り返されます。
正直、元のデザインの方がいいと思います。それは欠陥がありますが、より良いです。