初めてのデータベース設計:私はオーバーエンジニアリングしていますか?[閉まっている]


246

バックグラウンド

私はCSの1年生で、父親の中小企業でアルバイトをしています。実世界でのアプリケーション開発の経験はありません。私はPythonでスクリプトを書き、Cでいくつかのコースワークを書いていますが、このようなものはありません。

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

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

国際的なクライアントがすぐに始まる可能性があるので、それが発生した場合にデータベースが爆発しないようにしてください。現在、クライアントとしていくつかの大企業があり、部門が異なります(例:ACME親会社、ACMEヘルスケア部門、ACMEボディケア部門)。

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

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

スキーマを「落書き」のように「設計」し、3番目の形式に正規化するようにしました。私は、MySQLのワークベンチにそれを差し込むと、それはかなり私のためにすべてをした:
フルサイズのグラフィックはこちら

代替テキスト
(ソース:maian.org

実行するクエリの例

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

質問

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

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


131
初年度のCS学生の皆様へ:StackOverflowを引き続きご利用ください。あなたの質問は興味深く、よく書かれていて、役に立ちます。つまり、質問者の上位1%にいます。
アダムクロスランド2010

ディビジョンに他のディビジョンを含めることはできますか?その場合、「has」テーブルを使用して、Divisionが含まれているDivisionにリンクを戻すことができます。
Mark Schultheiss、2010

親切なコメントをありがとう:)マークこのプロジェクトのドキュメントをもう一度確認する必要がありますが、そのケースを特定できなかったと思います。指摘してくれてありがとう。
bob esponja

1
私はあなたの主キーの命名規則を好きではありません。テーブルにdivisionsはという列がありますdivisionid。冗長だと思いませんか?名前を付けるだけid。また、以下を含むテーブル名も_has_削除しcities_departmentsます。ユーザーが入力した値でない限り、DATETIME列のタイプを指定する必要がありTIMESTAMPます。citiescountriesテーブルを用意することをお勧めします。テーブルを1つに制限する問題が発生する可能性がありますstatus。を使用しINTて、ビット単位の比較を実行することを検討してください。これにより、そこでより多くの意味を保持できます
ジェームズ2015

@binnyb 主キーの名前としてidを使用することについては、決定する前に考慮すべき多くの議論があります。
ジェダイ

回答:


42

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

1)このような問題に初めて取り組む人にとって、あなたはほぼ目標を達成しています。この質問に関する他の人からのポインタは、これまでのところほとんどカバーしています。よくやった!

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

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

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

これらはすべて、作成するデータベースの役割によっては、採用する設計の原則と手法が異なる可能性があることを説明するために長続きします。お役に立てば幸いです。


1
1.ありがとう、心強い!2と3。インデックスがどのように機能するかはまだわかりません。これは、私が読み進める予定でした。100万レコードに達するという「問題」が発生した場合、経験豊富な開発者を雇うための予算がおそらくあるでしょう。あなたが説明するのは基本的にプロジェクトの最終目標なので、スナップショットを調べます。
bob esponja 2010

テーブルを理解していれば、インデックスの基本は非常に簡単です。概念的には、インデックスは、コンテンツがメインテーブルからコピーされるごく少数の列と、メインテーブルへの参照で構成されるテーブルとして実装できます。B + Treeは最も一般的なインデックスの配置ですが、インデックスの最適化は大きなプレーヤーが差別化技術を持っているため、アナロジーを深く適用しようとするとあいまいになります。
pojo-guy

14

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

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

その上、私はすべてがうまくいくと思います...


4
異なる部門や都市で部門定義を再利用する場合は、マッピングテーブルが必要だと思います。
Jacob G

1
はい、同意します.....しかし、部署は1つの都市/部門にしか存在できないようです。そうでなければ、彼が持っていたものは間違いなく正しかった。
Gonzo牧師

オフィスに「仕様」を書いたWiki記事があります。もう一度読む必要がありますが、Jacob Gは正解です。IIRCには部門にまたがる部門がいくつかあります。ACMEヘルスケアとACMEボディケアの両方のACME親の1つのHR部門。私が確かにそれを簡素化できるなら、提案をありがとう。
bob esponja

6

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

2-可能であれば、int IDをGUID(uniqueidentifier)に変更します(これは私の個人的な好みかもしれません)。最終的に複数の環境(dev / test / staging / prod)ができるようになったとすると、データを一方から他方に移行することができます。GUID IDがあると、これが大幅に簡単になります。

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

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


1-おかげで、私は別の質問を投稿するつもりの発音区別符号とUTF8で問題を抱えていました。多分これが問題です。2-私はここでSOについて他のいくつかの質問を読みましたが、この問題について多くの矛盾する意見があります。この件については、もっと読んでいきます。3-私はこれを私の父と再び話し合い、私が書いた「仕様」を見て、これが私たちが調査すべきものであるかどうかを確認します。
bob esponja

4-簡潔にするために、メインの質問では説明しませんでした。クライアントのステータスは、アクティブ(セッションが残っている)か非アクティブ(セッションが残っていない)かです。より明確に言うと、それはcolをより説明する名前を意味しますか?例:enrolment_status?ご入力いただきありがとうございます。
bob esponja

re#4-明確な名前に加えて、アクティブ/非アクティブの状態が2つしかない場合は、ビット列にしないでください。
Jacob G

3
GUIDについて同意しない、身震い。彼らはパフォーマンスにとって恐ろしいことができます。あなたがreplcipleする必要がない限り、それらを使用しないでください。
HLGEM 2010

1
パフォーマンスは、テーブル内の数千万行を話しているときにのみ効果を発揮します。そのタイプの構造がある場合は、シーケンシャルGUIDとクリエイティブインデックスを使用して軽減できます。それ以外の場合、GUIDを割り引くときの「パフォーマンス」は重要なニシンです。
Jacob G

6

いいえ。詳細レベルでデザインしているようです。

国と企業、そして都市と部門は、あなたのデザインにおいて本当に同じ実体であると思います。CountriesテーブルとCitiesテーブル(およびCities_Has_Departments)を削除し、必要に応じて、ブールフラグIsPublicSectorをCompaniesテーブル(または、民間セクター/公共セクターよりも選択肢が多い場合はCompanyType列)に追加します。

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

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


国の表は、複数の国で事業を展開していて、それぞれの国に異なる人事部があるクライアントがいるかどうかを示しています。このようにして、私たちが扱っている部門が活動している国のデータを使用してレポートを作成できます。部門と都市についても同じですが、HR部門が別々のクライアントがいると思います。少なくとも2つの都市にメインオフィスがある。あるいは、少なくともそれが理由だったので、座って考え直し、本当に必要かどうかを確認する。CompanyTypeについては考えていませんでしたが、追跡する必要があるかどうかを確認します。
bob esponja 2010

RE:deptsテーブル、私の最初の思考トラックは、実際の部門として使用し、部門名をタイプとして使用することでした。部署のタイプだけを持っていることは、私には思いもよらないことでした。どの部署とどこに所属しているかを知ることについては、部署を市や部署(会社にリンクしている)にリンクさせればうまくいくと思っていました。私は間違っていましたか?都市を分割に分割するために、いくつかの分割は複数の都市にまたがっています。おそらく国でさえあると思います。もう一度調べます。ご入力いただきありがとうございます。
bob esponja 2010

5

ちなみに、すでにCSVを生成していて、それらをmySQLデータベースにロードしたい場合は、LOAD DATA LOCAL INFILEが最適です。http//dev.mysql.com/doc/refman/5.1/ en / load-data.html。Mysqlimportも検討する価値があり、基本的にはデータをファイルにロードするための優れたラッパーであるコマンドラインツールです。


3

ほとんどのことはすでに述べられていますが、1つ付け加えることができると思います。若い開発者がパフォーマンスについて少し前から心配しすぎることは非常に一般的であり、テーブルの結合に関する質問はその方向に向かっているようです。これは、「時期尚早の最適化」と呼ばれるソフトウェア開発アンチパターンです。あなたの心からその反射を追放してみてください:)

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


1
私はかもしれませんが試してみてください、それはオベ服用し続ける計算にhelloworld.cの大きなOを、最適化私は3NFデータベースを取得するための手順を以下の時に都市や国のテーブルがちょうど一種の自分を生み出しました。彼らが提供する利点は、都市/国名の一貫性であると思います。ミュンヘンでクライアントを獲得した場合のように、何らかの理由で新しい学生をスケジューリングシステムに入力した人は、以前の学生のようにミュンヘンではなくミュンヘンと呼ぶことにします。また、部署を都市別にリストする必要があるかもしれません。確認する必要があります。ありがとう。
bob esponja 2010

2
データベースの設計段階での最適化は重要です。数百万のレコードがある場合、データベースを再構成することは非常に難しいため、時期尚早の最適化ではありません。
HLGEM 2010

1
私は彼が彼のデザインをストレステストすべきではないとは言いませんでした:)
Hans Westerbeek

3

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

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

  2. パックテーブルには「クレジット」列が含まれていますが、実際にはクライアントのベーステーブルに関連付けられているのではないので、パックが多い場合、将来のクラスに残されているクレジットの量を確認できますか?アプリケーションは計算を処理し、クライアントテーブルに集中的に格納できます。

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

  4. 事前にパッケージ化された「レポート」ソフトウェアを使用すれば、迅速かつはるかに少ない頭痛の種となる可能性のある大規模な開発イニシアチブに向けて準備する可能性がある、いくつのレコードを処理するかについては触れません。大規模なデータベース(<65000)の行を処理しない場合は、MS-Access、OpenOffice(Base)、または関連するレポート/アプリ開発ソリューションがうまくいかないことを確認してください。私はOracleの無料のAPEXソフトウェアをかなり自分で使用しています。無料のデータベースOracle XEが付属しているので、サイトからダウンロードするだけです。

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

よろしく。


1.これらの列をすべてクライアントテーブルに追加するということですか?それは正規化を壊し、一貫性を保つのを難しくするだろうと思いますが、正しく理解したかどうかはわかりません。2.パックはシーケンシャルであり、最新のパックのみがクレジットを未処理にできるため、複数のパックを追跡する必要はありません。この場合でも、クライアントテーブルに保存することをお勧めしますか?3.これは、クライアント企業の構造を理解するのに非常に役立つと思われます。ありがとうございます。
bob esponja 2010

4.来年に予定しているクライアントとセッションの数を確認する必要がありますが、セッションテーブルが1年程度でその数の行に到達することは現実的に思えます。私は報告ソフトウェアを調べますが、それは私には起こりませんでした。5.それが私が誤ってたどり着いた状況です。Webアプリが「トランザクションデータベース」となり、このプロジェクトが「リポッティングデータベース」となります。入力ありがとうございます。
bob esponja 2010

1.はい、「会社ID、部門の説明、部門の説明、部門タイプID、部門タイプID」列をクライアントテーブルに追加します。クライアントは1つの会社に属し、会社内の部門タイプ(IT / Ops / Admin / etc)と部門タイプ(Sales / HR / Marketing line of business)に属しています。2.私は、クレジットはクライアントまたは会社に関連付けられており、セッションのパックには関連付けられていないと思います。これは、ビジネス上の意思決定です。
ウィル

ラリーはまた、会社と国を組み合わせることに言及しました。私は完全に同意し、D&B参照に関するポイントに戻ります。同じ会社の複数の場所を許可するために、SiteIDまたは一意の何かを使用してから、部門を一意のSiteIDの1つにリンクします。
ウィル

2

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

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


1

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


列挙型は悪です。列挙型を拡張する必要があるたびに、テーブルを再構築する必要があります。これは、テーブルのサイズが数GBになるまで問題ありません。
マーティン

入力とクリスの提案のおかげで、私は過度に複雑なモンスターを作成するのではないかと心配しました。マーティン、ステータスはかなり明確で静的です:基本的に0-完全なクラス、1-クラスはキャンセルされました、2-は現れませんでした。これらの3つは、クラスのすべての可能な結果を​​カバーすると思います。この場合に列挙型を使用することはまだ悪い考えですか?
bob esponja

私の考えでは、これは列挙型に最適です。すべての可能な結果は、事前に満たされます。intも問題ありません。これをアプリの列挙型または静的intで表すことができます。本当に重要ではありません:)何らかのツールを使用してデータベースを編集する場合は、列挙型の方が見やすくなります。
Chris Dennett、2010

24時間年中無休でオンラインにする必要がある大きなテーブルがあり、列挙型を変更する必要がある場合、列挙型は問題となる可能性があります(おそらく悪が強すぎるかもしれません)。テーブルを最初から再作成する場合は、心配しないでください。データセットが十分に小さい場合、文字列を使用することもできます。
マーティン

1

私はトレーニング/学校のドメインで働いていましたが、「セッション」(特定のコースのインスタンス)と呼ばれるものとコース自体の間には一般にM:1の関係があると指摘しました。言い換えると、カタログはコース(「スペイン語101」など)を提供しますが、1学期中に2つの異なるインスタンスがある可能性があります(スミスが教えるトゥス、ジョーンズが教える水と金)。

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


私があなたを正しく理解しているのであれば、それはまったく当てはまりません。「コース」は、後続のセッションの単なるグループです。これは、従来の学期ベースのシステムではありません。他にクライアントドメインに追加できるものは考えられませんが、例はありますか?また、私はすでに複雑さのために船外に行ってしまったのではないかと心配していました。
bob esponja 2010

0

いくつかのことが頭に浮かびました:

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

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

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

  4. 中小企業であることを示しているので、現在のマシンの速度と容量を考えると、パフォーマンスが問題になるのは驚くべきことです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.