web-dev-qa-db-ja.com

初めてのデータベース設計:私は過剰設計ですか?

バックグラウンド

私はCSの1年生で、父の小規模ビジネスのためにパートタイムで働いています。私は実際のアプリケーション開発の経験がありません。私はPythonでスクリプトを書き、Cでいくつかのコースワークを書きましたが、このようなものはありません。

私の父は小規模なトレーニング事業を営んでおり、現在、すべてのクラスは外部Webアプリケーションを介してスケジュール、記録、フォローアップされています。エクスポート/「レポート」機能がありますが、非常に汎用的であり、特定のレポートが必要です。クエリを実行するために実際のデータベースにアクセスすることはできません。カスタムレポートシステムのセットアップを依頼されました。

私の考えは、一般的なCSVエクスポートを作成し、オフィスでホストされているMySQLデータベースに(おそらくPythonで)インポートし、そこから必要な特定のクエリを実行できるようにすることです。私はデータベースの経験はありませんが、基本を理解しています。データベースの作成と通常のフォームについて少し読みました。

私たちはすぐに国際的なクライアントを持つようになるかもしれないので、それが起こった場合/いつでもデータベースが爆発しないようにしたいです。また、現在、いくつかの大企業がクライアントとしてあり、部門が異なります(例:ACME親会社、ACMEヘルスケア部門、ACMEボディケア部門)

私が思いついたスキーマは次のとおりです。

  1. クライアントの観点から:
    • クライアントはメインテーブルです
    • クライアントは所属する部門にリンクされています
      • 部署は国中に散在しています:ロンドンのHR、スウォンジーのマーケティングなど。
      • 部門は会社の部門にリンクされています
    • 部門は親会社にリンクされています
  2. クラスの観点から:
    • セッションはメインテーブルです
      • 教師は各セッションにリンクされています
      • Statusidは各セッションに与えられます。例えば。 0-完了、1-キャンセル
      • セッションは、任意のサイズの「パック」にグループ化されます
    • 各パックはクライアントに割り当てられます

私は紙の上のスキーマを「デザイン」(落書きに似ている)し、3番目の形式に正規化された状態を維持しようとしました。その後、MySQL Workbenchにプラグインしましたが、とてもきれいになりました。
フルサイズのグラフィックはここをクリック

alt text
(ソース: maian.org

実行するクエリの例

  • 残っているクレジットを持つクライアントが非アクティブである(将来クラスが予定されていないクライアント)
  • クライアント/部門/部門ごとの出席率はいくらですか(各セッションのステータスIDで測定)
  • 1か月に教師が行ったクラスの数
  • 出席率が低いクライアントにフラグを立てる
  • 人事部門のカスタムレポートとその部門の出席率

質問

  • これは過剰設計されていますか、それとも正しい方向に向かっていますか?
  • ほとんどのクエリで複数のテーブルを結合する必要があると、パフォーマンスが大幅に低下しますか?
  • おそらく一般的なクエリになるため、クライアントに「lastsession」列を追加しました。これは良いアイデアですか、データベースを厳密に正規化しておく必要がありますか?

御時間ありがとうございます

244
bob esponja

あなたの質問に対するいくつかの答え:

1)あなたは、このような問題に初めて近づいている人をターゲットにしています。この質問に関する他の人からのポインタは、これまでのところほとんどカバーしていると思います。よくやった!

2&3)パフォーマンスヒットは、特定のクエリ/プロシージャ、さらに重要なことにレコードの量に対して適切なインデックスを作成し、最適化することに大きく依存します。メインテーブルの100万件をはるかに超えるレコードについて話しているのでない限り、合理的なハードウェアではパフォーマンスが問題にならないほど十分に主流の設計を行うことに順調に進んでいるようです。

とはいえ、これは質問3に関連しています。最初は、パフォーマンスや正規化の正統性に対する過敏性についてあまり心配するべきではありません。これは構築しているレポートサーバーであり、トランザクションベースのアプリケーションバックエンドではなく、パフォーマンスまたは正規化の重要性に関してプロファイルが大きく異なるものです。ライブサインアップおよびスケジューリングアプリケーションをサポートするデータベースは、データを返すのに数秒かかるクエリに注意する必要があります。レポートサーバー機能は、複雑で長いクエリに対する許容度が高いだけでなく、パフォーマンスを改善する戦略も大きく異なります。

たとえば、トランザクションベースのアプリケーション環境では、パフォーマンスの改善オプションとして、ストアドプロシージャとテーブル構造をn次までリファクタリングしたり、一般的に要求される少量のデータのキャッシュ戦略を開発したりできます。レポート環境では確かにこれを行うことができますが、スケジュールされたプロセスが実行され、事前構成されたレポートを保存するスナップショットメカニズムを導入することにより、パフォーマンスにさらに大きな影響を与えることができます。リクエストごとに。

これらはすべて、作成しているdbの役割を考えると、採用する設計原則とトリックが異なる可能性があることを示すための長々とした暴言です。それがお役に立てば幸いです。

42
Tom Crowe

あなたは正しい考えを持っています。ただし、クリーンアップして、マッピング(has *)テーブルの一部を削除できます。

できることはDepartmentsテーブルで、CityIdとDivisionIdを追加することです。

それに加えて、私はすべてがうまくいくと思います...

14
Reverend Gonzo

いいえ。詳細レベルで設計しているようです。

国と会社は、都市と部門と同様に、設計において実際に同じエンティティであると思います。国と都市のテーブル(およびCities_Has_Departments)を削除し、必要に応じて、ブール値のフラグIsPublicSectorを企業テーブル(または、プライベートセクター/公共セクター以外の選択肢がある場合はCompanyType列)を追加します。

また、Departmentsテーブルの使用法に誤りがあると思います。 Departmentsテーブルは、各顧客部門が持つことができるさまざまな種類の部門への参照として機能するようです。その場合、DepartmentTypesと呼ばれるべきです。しかし、あなたのクライアント(私は、出席者だと思います)は、部門TYPEに属していません。彼らは、会社の実際の部門インスタンスに属します。現状では、特定のクライアントがどこかのHR部門に属しているが、どの部門に属しているのではないことがわかります。

言い換えると、クライアントは、Divisions_Has_Departmentsと呼ぶテーブルにリンクする必要があります(ただし、単にDepartmentsと呼ぶことにします)。その場合、データベースで標準の参照整合性を使用する場合は、上記で説明したように都市を部門にまとめる必要があります。

6
Larry Lustig

私が行う唯一の変更は次のとおりです。
1- VARCHARをNVARCHARに変更します。国際化する場合は、ユニコードが必要になる場合があります。

2-可能であれば、int idをGUID(一意の識別子)に変更します(これは私の個人的な好みかもしれません)。最終的に複数の環境(dev/test/staging/prod)が存在するポイントに到達したと仮定すると、一方から他方にデータを移行することができます。 Have GUID Idsはこれを非常に簡単にします。

3-会社の3つの層->部門->部門構造では不十分な場合があります。現在、これはオーバーエンジニアリングの可能性がありますが、nレベルの深さをサポートできるように、その階層を一般化できます。これにより、クエリの一部がより複雑になるため、トレードオフに値しない場合があります。さらに、より多くのレイヤーを持つクライアントは、このモデルに簡単に「詰め込む」ことができます。

4-また、クライアントテーブルにVARCHARであるステータスがあり、ステータステーブルへのリンクがありません。クライアントステータスが何を表しているかについては、もう少し明確になると思います。

6
Jacob G

ところで、CSVを既に生成していてmySQLデータベースにロードしたい場合、LOAD DATA LOCAL INFILEがあなたの親友であることは注目に値します: http://dev.mysql.com/doc/ refman/5.1/en/load-data.html 。 Mysqlimportも検討する価値があります。これは、基本的に、ロードデータインファイルのニースラッパーであるコマンドラインツールです。

5
jrheard

ビジネスインテリジェンス/レポートスペシャリストおよび戦略/プランニングマネージャーとしての役割に基づいたコメント:

  1. 上記のラリーの指示に同意します。私見、それはあまりにも過剰に設計されていない、いくつかのものは少し場違いに見える。簡単にするために、クライアントに会社ID、部門の説明、部門の説明、部門のタイプID、部門のタイプIDを直接タグ付けします。長期的な一貫性を保つために、ルックアップテーブルおよび内部レポート/分析フィールドへの参照として部門タイプIDおよび部門タイプIDを使用します。

  2. Packsテーブルには「Credit」列が含まれますが、実際にはこれをClientベーステーブルに結び付けてはいけません。したがって、パックが多ければ、将来のクラスにどれだけのクレジットが残っているかを確認できますか?アプリケーションが計算を処理し、Clientテーブルに一元的に保存できます。

  3. 会社情報では、明らかな住所/電話番号など、さらに多くのフィールドを使用できます。情報。また、D&Bの「DUN」列(サイト/ブランチ/アルティメット)を長期的に追加する準備ができています。Dunand Bradstreet(D&B)には企業の膨大なカタログがあり、後で情報が非常に役立つことがわかりますレポート/分析用。これにより、あなたが言及した複数の部門の問題が処理され、sub/division/branches/etcの階層をロールアップできます。大軍団の。

  4. 事前にパッケージ化された「レポート」ソフトウェアを使用すれば、より迅速ではるかに少ない頭痛の種であった大規模な開発イニシアチブに自分自身を設定することを意味する、作業するレコードの数については言及しません。大規模なデータベース(65000未満)行を扱っていない場合は、MS-Access、OpenOffice(Base)、または関連するレポート/アプリ開発ソリューションがうまくいかないことを確認してください。私はオラクルの無料のAPEXソフトウェアをかなり自分で使用しています。無料のデータベースOracle XEに付属しており、サイトからダウンロードするだけです。

  5. 参考-洞察の報告:大規模なデータベースの場合、通常、2つのデータベースインスタンスがあります。a)各詳細レコードを記録するためのトランザクションデータベース。 b)別のマシンに格納されているレポートデータベース(データマート/データウェアハウス)。詳細については、Googleでスタースキーマとスノーフレークスキーマの両方を検索してください。

よろしく。

3
Will

ほとんどのことはすでに言われていますが、私は1つ付け加えることができると思います:若い開発者がパフォーマンスについて少し前もって心配することは非常に一般的であり、テーブルへの参加についてのあなたの質問はその方向に行くようです。これは、「 Premature Optimization 」と呼ばれるソフトウェア開発のアンチパターンです。あなたの心からその反射を追放してみてください:)

もう1つ:「都市」と「国」のテーブルが本当に必要だと思いますか?部門テーブルに「都市」列と「国」列があれば、ユースケースには十分ではないでしょうか?例えば。アプリケーションは、都市ごとに部門を、国ごとに都市をリストする必要がありますか?

3
Hans Westerbeek

複数のテーブルに参加するとパフォーマンスが低下するという懸念のみに対処したいと思います。結合する必要があるため、正規化を恐れないでください。結合は通常であり、リレーショナルデータベースでは期待されており、それらを適切に処理するように設計されています。 PK/FK関係を設定する必要があります(データの整合性のために、これは設計時に考慮することが重要です)が、多くのデータベースではFKが自動的にインデックス付けされません。これらは結合で使用されるため、FKSにインデックスを付けることから始めてください。 PKは一意である必要があるため、通常は作成時にインデックスを取得します。データウェアハウスの設計によって結合の数が減ることは事実ですが、通常、1つのレポートで何百万ものレコードにアクセスする必要があるまで、データウェアハウジングのポイントには達しません。その場合でも、ほとんどすべてのデータウェアハウスは、トランザクションデータベースから開始してリアルタイムでデータを収集し、その後スケジュールに従って(夜間または毎月、またはビジネスのニーズに応じて)データをウェアハウスに移動します。したがって、レポートのパフォーマンスを向上させるために後でデータウェアハウスを設計する必要がある場合でも、これは良い出発点です。

あなたのデザインは、CSの1年生にとって印象的だと言わざるを得ません。

2
HLGEM

それは過剰に設計されていないので、これが私が問題に取り組む方法です。結合は問題ありませんが、パフォーマンスに大きな影響はありません(推奨されないデータベースの正規化を解除しない限り、完全に必要です!)。ステータスについては、代わりにenumデータ型を使用してそのテーブルを最適化できるかどうかを確認してください。

1
Chris Dennett

私はトレーニング/学校の分野で働いてきましたが、一般的にあなたが「セッション」(特定のコースのインスタンス)と呼ぶものとコース自体の間にM:1の関係があると指摘したいと思いました。つまり、カタログはコース(「スペイン語101」など)を提供しますが、1学期中に2つの異なるインスタンスを持っている可能性があります(Tu-Thがスミスに教え、Wed-Friがジョーンズに教えます)。

それ以外は、良いスタートのようです。クライアントドメイン(「クライアント」につながるグラフ)は、モデル化したものよりも複雑であることに気付くでしょうが、実際のデータが得られるまで、それを使いすぎないでください。

1
Larry OBrien

いくつかのことが思い浮かびました。

  1. 表はレポート作成用に調整されているように見えましたが、実際にはビジネスを運営していません。クライアントがサインアップすると、セッションのリストに参加しているクライアントに対して基本的に注文が行われ、その注文は1つの会社の複数の従業員に対して行われる可能性があると思います。 「注文」テーブルが実際にシステムの中心にあり、データキャプチャと最終的なレポートを駆動しているように見えます。 (データベース設計でビジネスを実行するために使用してきた紙の文書を比較して、論理的な一致があるかどうかを確認します。)

  2. 多くの場合、企業には部門がありません。従業員は部門/部門を変更することもありますが、途中で変更することもあります。企業は、部門/部門を追加/削除/名前変更することがあります。テーブルの内容をリアルタイムで変更しても、その後のレポート/グループ化が難しくならないようにしてください。連絡先データが非常に多くのテーブルに分割されているため、レポートを有意義かつ包括的に保つために、非常に厳密なデータ入力検証を実施する必要があります。たとえば、新しいクライアントが追加されたとき、彼の会社/部門/部門/都市が同僚と同じ値に一致することを確認します。

  3. 「パック」の概念はまったく明確ではありません。

  4. あなたはそれが小規模ビジネスであることを示しているので、現在のマシンの速度と容量を考慮すると、パフォーマンスが問題になる場合は驚くでしょう。

0
joe snyder