8

アプリケーションには、後でアクセスするために参照を保存する必要があるという要件があります。

例: ユーザーは一度に請求書をコミットでき、この請求書に含まれるすべての参照 (顧客の住所、計算された金額、製品の説明) と計算は長期にわたって保存する必要があります。

何らかの方法で参照を保持する必要がありますが、たとえば製品名が変更された場合はどうなりますか? したがって、何らかの形ですべてをコピーして、後で文書化して将来の変更の影響を受けないようにする必要があります。製品が削除された場合でも、後で請求書が保存されるときにレビューする必要があります。

データベース設計に関するベスト プラクティスは何ですか? ユーザーが後で請求書を編集してデータベースから復元したい場合など、最も柔軟なアプローチは何ですか?

ありがとうございました!

4

5 に答える 5

11

これを行う1つの方法は次のとおりです。

ここに画像の説明を入力してください

基本的に、既存のデータを変更または削除することはありません。新しいバージョンを作成して「変更」します。DELETEDフラグを設定して「削除」します。

例えば:

  • 製品が価格を変更した場合、古い注文が古いPRODUCT_VERSIONと古い価格に接続されたまま、新しい行がPRODUCT_VERSIONに挿入されます。
  • 購入者が住所を変更すると、CUSTOMER_VERSIONに新しい行を挿入し、古い注文を古いバージョンにリンクしたまま、新しい注文をそれにリンクするだけです。
  • 製品が削除された場合、実際には削除されません。PRODUCT.DELETEDフラグを設定するだけなので、その製品に対して過去に行われたすべての注文がデータベースに残ります。
  • 顧客が削除された場合(たとえば、顧客が登録解除を要求したため)、CUSTOMER.DELETEDフラグを設定します。

警告:

  • 製品名を一意にする必要がある場合、上記のモデルで宣言的に強制することはできません。NAMEをPRODUCT_VERSIONからPRODUCTに「プロモート」するか、そこでキーにして製品名を「進化」させる機能を放棄するか、最新のPRODUCT_VERのみに一意性を適用する必要があります(おそらくトリガーを介して)。
  • お客様のプライバシーに潜在的な問題があります。顧客がシステムから削除された場合、データベースからそのデータを物理的に削除することが望ましい場合があり、CUSTOMER.DELETEDを設定するだけではそれは行われません。それが懸念される場合は、すべての顧客のバージョンでプライバシーに配慮したデータを空白にするか、既存の注文を実際の顧客から切断して特別な「匿名」の顧客に再接続してから、すべての顧客のバージョンを物理的に削除します。

このモデルは、多くの識別関係を使用します。これは「太った」外部キーにつながり、MySQLは最先端のインデックス圧縮をサポートしていないため(たとえばOracleとは異なり)、ストレージの問題になる可能性がありますが、一方、InnoDBは常にPKとこれにデータをクラスタリングしますクラスタリングはパフォーマンスに役立つ場合があります。また、JOINの必要性も少なくなります。

非識別関係と代理キーを持つ同等のモデルは、次のようになります。

ここに画像の説明を入力してください

于 2012-06-11T21:58:52.027 に答える
1

製品テーブルに、販売されているかどうかを示す列を追加できます。次に、製品が「削除」されたときに、新しい製品として使用できなくなるようにフラグを設定しますが、将来のルックアップのためにデータを保持します。

名前の変更に対処するには、名前を直接使用するのではなく、IDを使用して製品を参照する必要があります。

于 2012-06-11T19:55:58.943 に答える
1

あなたは、純粋主義的アプローチと実践的アプローチの間の永遠の議論を開きました.

データベースの正規化の観点から、関連するすべてのデータを保持する必要があります。つまり、製品名が変更された場合、変更の日付を保存して、時間をさかのぼってその製品名で請求書を再構築し、その日に存在していた他のすべてのデータを作成できるようにします。

「非」正規化アプローチは、その請求書を「ある瞬間」として表示し、関連するテーブル データに実際の当日のデータを記録することです。このアプローチでは、依存関係がまったくない状態でその請求書を取得できますが、その請求書をゼロから再作成することはできません。

于 2012-06-11T20:01:47.343 に答える
1

あなたが直面している問題は、ご存じのとおり、データベースの正規化の結果です。これを解決するためのアプローチの 1 つは、ビジネス インテリジェンス技術から得られるもので、データ ウェアハウスにデータを非正規化状態でアーカイブすることです。

正規化されたデータ:

  • 注文表
    • オーダーID
    • 顧客ID
  • 顧客テーブル
    • 顧客ID
    • ファーストネーム
  • 品目表
    • アイテム ID
    • 項目名
    • 商品価格
  • OrderDetail テーブル
    • ItemDetailId
    • オーダーID
    • アイテム ID
    • 品目数量

クエリを実行して非正規化して保存すると、データ ウェアハウス テーブルは次のようになります。

  • オーダーID
  • 顧客ID
  • 顧客名
  • 顧客住所
  • (その他の顧客分野)
  • ItemDetailId
  • アイテム ID
  • 項目名
  • 商品価格
  • (その他の OrderDetail および Item フィールド)

通常、定期的に正規化されたデータからデータ ウェアハウスにデータをプルする何らかのスケジュールされたジョブが存在するか、設計が許す場合は、注文が特定のステータスに達したときに実行できます。(発送済みなど) ステータスが変化するたびに (現在のステータスを追跡する OrderStatus というフィールドを使用して) レコードが保存される可能性があるため、完全に非正規化されたデータを注文/フルフィルメント プロセスの各ステップで使用できます。データをウェアハウスにアーカイブする時期と方法は、ニーズによって異なります。


上記には多くのオーバーヘッドが伴いますが、私が知っているもう 1 つの一般的なアプローチでは、さらに多くのオーバーヘッドが発生します。

もう 1 つの方法は、テーブルを読み取り専用にすることです。顧客が住所を変更したい場合、既存の住所を編集するのではなく、新しいレコードを挿入します。

したがって、Jamnuary であなたのサイトで最初に注文したときに私の住所が AddressId 12 だった場合、7 月 4 日に移動すると、アカウントに関連付けられた新しい AddressId が取得されます。(あなたのサイトは非常に成功しており、多くの顧客を引き付けているため、AddressId 123123 とします。)

7 月 4 日より前に行った注文には AddressId 12 が関連付けられ、7 月 4 日以降に行われた注文には AddressId 123123 が関連付けられます。

履歴データを保持する必要があるすべてのテーブルで、このパターンを繰り返します。


私は 3 番目のアプローチを持っていますが、それを探すのは困難です。私はこれを 1 つのアプリでのみ使用していますが、実際には、特定の時点でのデータを正確に再構築するという非常に具体的なビジネス ニーズがあったこの 1 つのインスタンスでかなりうまく機能します。同様のビジネスニーズがない限り、私はそれを使用しません。

特定の状態で、データを Xml ドキュメント、またはデータの再構築に使用できるその他のドキュメントにシリアル化します。これにより、シリアル化された時点のデータを保存し、元のテーブル構造と関係を保持できます。

于 2012-06-11T19:59:50.477 に答える
0

時間依存のデータがある場合は、product テーブルや Customer テーブルなどをルックアップ テーブルとして使用し、Orders/orderdetails テーブルに情報を直接保存します。

そのため、注文テーブルには顧客の名前と住所が含まれる場合があり、詳細には、特に価格を含む製品に関するすべての関連情報が含まれます (注文時の最初のルックアップを超えて価格情報を製品テーブルに依存することは決してありません)。

これは非正規化ではありません。データは時間の経過とともに変化しますが、履歴値が必要なため、レコードが作成された時点で保存する必要があります。そうしないと、データの整合性が失われます。価格が更新されたために、昨年の売上高が 30% 増加したことを突然財務レポートに表示したくありません。それはあなたが売ったものではありません。

于 2012-06-11T20:50:48.377 に答える