web-dev-qa-db-ja.com

データベース設計を非正規化する場合

Stack Overflowで正規化が広範囲にわたって議論されてきたことを知っています。これまでの議論の多くを読みました。でもいくつか質問があります。

少なくとも100のテーブルがあるレガシーシステムで作業しています。データベースには、いくつかの非正規化された構造、さまざまな異種データを含むテーブル、およびその他の問題があります。私はそれを改善しようとする仕事を与えられました。最初からやり直すことはできませんが、既存のスキーマを変更する必要があります。

過去には、常に正規化されたデータベースを設計しようとしました。さて、質問です。上級開発者は、一部のケースでは正規化できないと示唆しています。

1)時系列データ。たとえば、製品にリンクする請求書が作成されます。 1年後に顧客がこの請求書のコピーを要求した場合、元の正確なコピーを作成できなければなりません。製品の価格、名前、または説明が更新された場合はどうなりますか?年配の男性は、価格やその他の製品情報を請求書テーブルにコピーすることを提案しました。時間の経過に伴う価格の変化を追跡できるように、日付フィールドを持つproductPriceなどの別のテーブルが必要になると思います。製品の説明と名前にも同じものが必要でしょうか?複雑そうです。どう思いますか?

2)データベースは会計システムです。私は会計にあまり詳しくありません。現在、いくつかの要約データが導出され、データベースに格納されています。たとえば、年間の合計売上高。私のシニアアソシエイトは、この値を請求書などから実際に計算されたデータと比較して、アプリケーションが正しく機能していることを確信させることで、物事が正しいことを確認したいと言っています。

たとえば、現時点では合計が同じにならないため、誰かが誤って昨年の請求書を削除したかどうかを判断できると彼は言った。また、これらの合計をその場で計算するのは非常に遅くなる可能性があることも指摘しました。もちろん、データは重複してはならず、必要なときに常に計算する必要があると述べました。私は、SQL Reporting Servicesまたはこれらのレポートを夜間に生成してキャッシュする他のソリューションを使用することを提案しました。とにかく彼は確信していません。これについて何かコメントはありますか?

47
Mark Evans

あなたの上級同僚は開発者であり、データモデラーではありません。ゼロから始めた方がいいでしょう。正規化は、本を読まない人やwikiのアマチュアから「知識」を得る人だけに複雑です。彼があなたに考えさせるほど十分に公平ですが、いくつかの問題はばかげています。

あなたの番号:

  1. 実際のオンラインデータと過去のデータの違いを理解する必要があります。次に、単に歴史的なニーズとアーカイブのニーズの違い。それらはすべて、特定のビジネス要件に対しては適切であり、他のすべてに対しては誤りであり、普遍的な権利と誤りはありません。

    • 請求書の紙ベースのコピーがないのはなぜですか?法的および税務上の要件となるほとんどの国で、古い請求書を釣り上げるのは正確にどのくらい難しいですか?
    • データベースには、クローズされた請求書を保存する要件があり、請求書がクローズされるとすぐに、その情報を取得する方法が必要になります。
    • ProductPrice(実際にはProductDateと呼びます)は良い考えですが、必要ないかもしれません。しかし、あなたは正しい、データベース全体の完全なコンテキストで、データの最新性を評価する必要があります。
    • 製品の価格を請求書テーブルにコピーするとどのように役立つかわかりません(多くの品目はありませんか?)
    • 最新のデータベースでは、請求書のcopyを逆流する必要がある場合、クローズされた請求書は、XMLなどの別の形式でさらに保存されます。 1人の顧客がPDFをBLOBとして保存します。したがって、5年前の製品価格をいじる必要はありません。ただし、基本的な請求書データは、クローズされた請求書であってもオンラインで最新のものです。現在の価格を使用して古代の請求書を再計算することはできません。
    • 一部の人はarchive_invoiceテーブルを使用しますが、すべてのコードセグメントまたはユーザーレポートツールが2か所を参照する必要があるため、問題が発生します(最近のユーザーは、ほとんどの開発者よりもデータベースをよく理解していることに注意してください)。
    • とにかく、それはあなたの理解のためのすべての議論です。私が30年以内に作成したデータベースのいずれも、そのような問題を抱えたことはなく、それらのすべてが法的要件および税務要件に準拠しています。
      • データベースは、1組のテーブル(「アーカイブ」テーブルはありません)から現在およびアーカイブの目的を果たします
      • 作成された請求書は法的文書であり、変更または削除することはできません(負の値を使用して、新しい請求書を元に戻したり、部分的に入金することができます)。それらは_IsIssued/IsPaid/Etc_とマークされています
      • Productsは削除できません。マークを付けることができますIsObsolete
      • InvoiceHeaderとInvoiceItemには別々のテーブルがあります
      • InvoiceItemにはInvoiceHeaderProductの両方に対するFKがあります
      • 多くの理由で(あなたが言及したものだけでなく)、InvoiceItem行には_NumUnits; ProductPrice; TaxAmount; ExtendedPrice_が含まれます。確かに、これは「非正規化」のように見えますが、価格、課税率などが変更される可能性があるため、そうではありません。しかし、より重要なことは、法的要件は、古い請求書をオンデマンドで再現できることです。
      • (紙のファイルから複製できる場合、これは必須ではありません)
      • InvoiceTotalAmountは派生列であり、InvoiceItemsのSUM()のみです
  2. それはごみです。会計システムと会計士はそのように「機能」しません。

    • それが真の会計システムである場合、JournalEntriesまたは「ダブルエントリ」を持ちます。これは、(法律により)適格アカウントを使用するために必要なものです。

      • 二重エントリーは重複エントリーを意味しません。つまり、すべての金融取引(1つの金額)には、適用されるソースアカウントとターゲットアカウントが必要です。したがって、「非正規化」や重複はありません。銀行取引データベースでは、金融取引は単一の口座に対するものであるため、通常、1つのDBトランザクション内で2つの別個の金融取引(行)としてレンダリングされます。通常の商用データベースの制約は、すべての金融取引に2つの「側面」があることを保証するために使用されます。
    • 請求書が削除可能でないことを保証することは、セキュリティなどの問題とは別に、別の問題です。誰かがデータベースから削除されることに偏執している場合、and資格のある人物によってデータベースが保護されていなかった場合、この質問とは何の関係もない、より多くの異なる問題があります。セキュリティ監査を取得し、彼らがあなたに言うことを何でもしてください。

    • このサイトには、wikiが何かを学ぶことができる場所だと思う人が何人かいます。そうではありません。それはアマチュアによって書かれた「定義」の汚名であり、「定義」は他のアマチュアによって常に変更されます。信頼できる固定の定義はありません。ですから、wikiの発言やwikiの発言について心配する必要はありません。彼らがwikiに言及した瞬間、彼らの「知識」は資格ではないことを読んでいることに気付きます。そして彼らが読んでいるのは、絶えず変化する墓場です。彼らは実際には経験がないので、「定義」について予想通りに議論するでしょう。経験豊富な人は仕事を始めるだけです

    • 正規化されたデータベースは、常に非正規化されたデータベースよりもはるかに高速です。したがって、正規化と非正規化とは何か、およびそうでないことを理解することが非常に重要です。人々が流動的でアマチュアの「定義」を持っている場合、プロセスは大きく妨げられ、混乱と時間の浪費となる「議論」につながります。定義が決まったら、それをすべて回避して、仕事を続けることができます。

    • サマリーテーブルは、時間と処理能力を節約するために、変化しない情報を再計算することで非常に正常です。たとえば、次のとおりです。 MTDは今年の毎月の合計ですが、今月は合計されません。 「常に再計算する」データは、(a)情報が非常に大きく、(b)変化しない場合、少しばかげています。当月のみ計算する

      • 銀行システム(1日あたり数百万の取引)では、EndOfDayで日次合計も計算して保存します。監査人が変更を加えているため、これらは過去5日間上書きされ、過去5日間の金融取引に対するJournalEntriesが許可されます。
      • 非銀行システムは、通常、日次合計を必要としません
    • サマリーテーブルは「非正規化」ではありません(魔法のように変化する流体の「ソース」から「正規化」について学んだばかりの人、または単純な黒または白のルールを適用する非実践者としての目を除く)すべてに)。繰り返しますが、定義はここでは議論されていません。単にサマリーテーブルには適用されません

    • サマリーテーブルは、データの整合性には影響しません(もちろん、それらのソースとなるデータが不可欠であると想定しています)。

    • サマリーテーブルは追加であり、データベースと同じ制約を持つ必要はありません。データベーステーブルとは対照的に、レポートテーブルまたはデータウェアハウステーブルがあります。

    • サマリーテーブルに関連する更新の異常(厳密な定義)はありません。昨年の請求書を変更または削除することはできません。更新異常は、真の非正規化または非正規化の現在のデータに適用されます。

44
PerformanceDBA

1)これはアーカイブです。そこにあるものはすべて更新すべきではありません。私は年配の人の提案に従い、その請求書テーブルを自己完結型にします。おそらく、マークアップ言語を含む請求書自体にblobを使用しますか?

2)レポートサービス、トリガーで更新されるウェアハウステーブル、スクリプトによっていつでも作成するもの...これらはすべて問題ないと思います。正規化することは確かに理想的ですが、常に高速であるとは限りません。私が管理する適切なサイズのヘルスケアデータベースがあり、これは完全に正規化されています...そして、ロールアップされた方程式と一般的にプルされたフィールドを含む一連の非正規化テーブルがあります。ほとんどすべてがその非正規化されたセットから実行されます.100,000件のレコードレポートを確認するたびにさまざまなテーブルからプルし続ける必要があるよりも、ファイルが読み込まれたときにトリガーでこれらに追加する方が高速です。

9
Jeff Ferland

あなたは有効なポイントを上げますが、正規化とその意味が完全に明確ではありません。たとえば、

1)請求書を非正規化したままにしておくと、データが完全かつ完全に間違っているという主張。たとえば、価格を考えてみましょう。価格の履歴を保持する必要があるというビジネス要件がある場合、現在の価格のみを保持することは間違っていて、要件を破ります。そして、それは正規化とは何の関係もなく、単にうまく設計されていないだけです。非正規化とは、モデル(および他のアーティファクト)に曖昧さの可能性を導入することです。この場合、問題の空間を適切にモデル化していないだけです。
テンポラルデータをサポートするようにデータベースをモデル化することには何の問題もありません(または、データベースのエリアをアーカイブ/テンポラルとワーキングセットにバージョン付けおよび/または分離します)。

(要件の観点から)セマンティクスを確認せずに正規化を確認することはできません。

また、上級開発者が違いを確認できない場合は、RDBMS開発での年功序列を得られなかったと思います;)

2)2番目の部分は確かに非正規化です。ただし、正規化を真剣に説得する上級DBアナリストに出くわした場合、意識的にそれを行い、過体重不足の利点と異常があなたに噛まないことを確実にする限り、正規化を解除することは完全に許容できると彼/彼女が言うのを聞くでしょう。また、論理モデルを正規化するように指示し、物理モデルでは、さまざまな目的(パフォーマンス、メンテナンスなど)の理想から逸脱することを許可されます。私の本では、正規化の主な目的は、隠れた異常がないようにすることです(たとえば、この記事の 5NF を参照してください)。

中間結果のキャッシュは、正規化されたデータベースでも、正規化の最大の伝道者でも許可されます-アプリケーション層で(ある種のキャッシュとして)実行するか、データベースレベルで実行するか、またはデータウェアハウスを使用してそのような目的。これらはすべて有効な選択であり、論理モデルの正規化とは何の関係もありません。

また、あなたの会計士に関しては-あなたは彼が主張しているものがnot良いテストであることを彼に納得させ、そしてテストの自動化を行う一連のテスト(おそらく彼と一緒に)を開発することができるはずです。ユーザーの介入なしのシステムであり、システムにバグがないことをより信頼できます。

一方、実際の行を入力する前または後に請求書に行数を入力するなど、入力が完全であることを確認するために、ユーザーが重複する情報を入力する必要があるシステムを知っています。このデータは「複製」され、入力を検証するプロシージャがある場合は、データを保存する必要はありません。その手順が後で来る場合、「非正規化」データを格納することが許可されます-再度、意味論はそれを正当化し、正規化されたモデルを見ることができます。 (この概念に頭を包むことは有益です)

EDIT:(2)の「非正規化」という用語は、通常のフォームの正式な定義を見て、次の場合に非正規化された設計を検討する場合は正しくありません。これは、通常の形式のいずれかを壊します(一部の人にとっては、これは明白であり、他の方法はありません)。

それでも、データベースの冗長性を減らそうとするあらゆる努力のために、多くの人々が必要のない不要なテキストで正規化という用語を使用するという考えに慣れる必要があるかもしれません(例として、科学論文が見つかります)これは正しいことだとは言いませんが、これは一般的であるという警告と同様に、派生属性を非正規化の形式と呼びます here を参照)。

さらに一貫性のある認識された当局に言及したい場合(ここでも、全員に認識されていません)、C.J.Dateの単語で明確に区別できます。

設計理論の多くは、冗長性の削減に関係しています。正規化はrelvar内の冗長性を減らし、直交性はrelvar全体で冗長性を減らします。

qouted from データベースの詳細:関係者のための関係理論

そして次のページ

完全に正規化できないと冗長性が生じ、特定の異常が発生する可能性があるのと同様に、直交性を維持できない場合もあります。

したがって、relvar間の冗長性の適切な用語は直交性です(基本的にすべての正規形は単一のrelvarについて話しているので、正規化を厳密に見ると、2つの異なるrelvar間の依存関係による改善を示唆することは決してありません)。

とにかく、データベースの設計を検討する際の他の重要な概念の1つは、論理データベースモデルと物理データベースモデルの違いでもあります。小計やインデックスのあるテーブルなど、物理レベルで役立つ多くのことは、論理モデルには場所がなく、モデル化しようとしている概念間の関係を確立して調査しようとします。そしてそれがあなたがそれらが許容され、デザインを台無しにしないと言える理由です。

線は、論理モデルと物理モデルとで少しぼやけている場合があります。特に良い例は、小計を含むテーブルです。それを物理的な実装の一部と見なし、論理的なレベルで無視するには、次のことを行う必要があります。

  • ユーザー(およびアプリケーション)が、述語と一致しない方法で小計テーブルを直接更新できないことを確認します(言い換えれば、小計手順にバグがあります)。
  • ユーザー(およびアプリケーション)が、小計を更新せずに、これらが依存しているテーブルを更新できないことを確認します(つまり、一部のアプリケーションは、合計を更新せずに詳細テーブルから行を削除しません)。

上記のルールのいずれかを破ると、最終的にinconsistent databaseとなり、inconsistent factsが提供されます。 (このような場合、発生した問題を修正または調査するための手順を正式に設計する場合、それは単なる追加のテーブルとは見なされず、論理レベルに存在するはずです。

また、正規化は常に、モデル化しようとしているセマンティクスとビジネスルールに依存します。たとえば、DBAPerformanceは、トランザクションテーブルにTaxAmountを格納することが非正規化された設計ではない例を示していますが、モデル化しようとしているシステムの種類に依存していることには言及していません(それは明らかですか?)。たとえば、トランザクションにTaxRateという別の属性がある場合、非キー属性のセットに機能的な依存関係があるため、通常は非正規化されます(TaxAmount = Amount * TaxRate => FD:Amount、TaxRate-> TaxAmount) 、およびこれらの1つを削除するか、整合性を保証する必要があります。

言うまでもないかもしれませんが、構築しているシステムが監査会社向けである場合は、機能的な依存関係がない可能性があります-手動計算を使用している人、ソフトウェアに欠陥がある人、不完全なデータを記録する能力が必要な人を監査している可能性があります元々計算が間違っている可能性があり、監査会社として、あなたはそれが起こったときに事実を記録しなければなりません。

したがって、要件によって決定されるセマンティクス(述語)は、正常なフォームが壊れているかどうかに影響します。つまり、機能の依存関係に影響を与えます(つまり、正規化されたデータベースを作成する場合、機能の依存関係を正しく確立することがモデリングの非常に重要な部分です)。

7
Unreason

あなたの上級開発者は非常に有効なポイントを作ります。私は、過去のデータを非正規化しないシステムにサービスを提供することで、これらの方法を自分自身で学びました。

ある意味では、データベースにオーバーヘッドを追加することにはなりません。データベースの既存のデータから請求書テーブルを作成しています。請求書は、適時のスナップショットです。その請求書を作成するために必要な情報を非正規化すると、レポート作成を簡単にすることができますSO新しいレポートを作成する必要があり、それを迅速に実行することが期待される場合は、非正規化に感謝します。

データベースに合計を持つという点で。これにより、アプリケーションに変更を加えたときに、数値が同じように加算されない(思ったほど難しくはない)ときに、私のお尻が救われました。ライブアプリケーションでは、合計により、矛盾を修正するために戻る場所が明確になりました。これについては以前に書いたことがありますが、ここで読むことができます。 http://jlrand.com/?p=95

4
Jonathan Rand

(1)について先輩に同意します。トランザクションテーブルの行は、トランザクションの瞬間の状態全体をキャプチャする必要があります。限目。あなたが提案しているものは実際のデータを記録しないので、それは許されません。 (2)についても同意します。クロスチェックによってビジネスが望むものは何でも、実装する必要があります。会計はクロスチェック、ダブルエントリー、元帳の積み上げなどに基づいています。あなたはそれをしなければなりません。これは非常に基本的であるため、ビジネス要件を実装するのと同じように、非正規化と見なすべきではありません。

4
user207421

1)非正規化は必要ありません。必要な各変更の詳細レベルを決定し、適切なキーでそれを維持するだけです。

2)非正規化とは何の関係もありません。概要データを保存しても、データベースは非正規化されません。非キー属性から導出された結果を保存する同じテーブル内は非正規化の例ですが、それはここで話していることではないようです。

3
nvogel

#1の場合

請求書は、売上と支払いから計算する必要があります。価格、製品、割引、送料などの詳細な販売データがない場合は、そこから開始してください。

#2の場合

会計システムをゼロからdbに書き込むことは大きなプロジェクトです。システムの正確さを測定できるように、会計士にビジネスルールを提供するようにしてください。あなたが望む最後のことは、DBAミーティングへのCFOステップであり、DBが顧客に過大な負担をかけていることを発表します。

SQL Serverをお持ちの場合は、Adventure Works dbをご覧ください。 MSが嫌いなら、Adventure Worksを見て、そのようにしないでください。

1
RC_Cleland

データウェアハウスを作成する必要があるかどうかを検討しているようです。履歴レポートの目的でデータベースを非正規化しないでください。アーカイブを作成してデータウェアハウスに情報を保存すると、ほとんどの情報が非正規化され、データ履歴が維持されます。

0
Lesly Revenge

データベースの正規化により、重複が削除され、データ更新のためのSQLクエリがより効率的になります(他のいくつかの改善も行われます)。

ただし、ほとんどのクエリがデータ選択に使用され、選択クエリが一度に複数のテーブルに接続する場合は、これらのテーブルの非正規化を検討できます。データに必要なディスク容量を増やし、SQL更新クエリの実行時間を増やしますが、選択クエリを改善します。

0
Alexandr