15

この質問は、私の他の質問の 1 つにあるスキーマに関連しています 基本的に、私のデータベースには、ユーザー、場所、センサーなどを保存しています。これらはすべて、ユーザーがシステム内で編集可能であり、削除可能です。

ただし、アイテムが編集または削除されると、古いデータを保存する必要があります。変更前のデータを確認できる必要があります。

データベースには、「読み値」など、編集できない項目もあります。それらは実際にはログのようなものです。特定のセンサーの読み取り値であるため、読み取り値はセンサーに対してログに記録されます。

読み取り値のレポートを生成する場合、読み取り時の位置またはセンサーの属性を確認できる必要があります。

基本的に、いつでもデータを再構築できるはずです。

さて、私は以前にこれを行ったことがあり、編集可能な各テーブルに次の列を追加することでうまく機能しました。

valid_from
valid_to
edited_by

valid_to = 9999-12-31 23:59:59 の場合、それが現在のレコードです。valid_to が valid_from と等しい場合、レコードは削除されます。

しかし、外部キーの一貫性を強制するために必要なトリガーには決して満足できませんでした。

「PostgreSQL」データベースの拡張機能を使用することで、トリガーを回避できる可能性があります。これにより、「期間」と呼ばれる列タイプが提供され、2 つの日付の間の期間を格納できるようになり、期間の重複を防ぐために CHECK 制約を実行できるようになります。それが答えかもしれません。

別の方法があるかどうか疑問に思っています。

特別な履歴テーブルの使用について言及している人を見てきましたが、ほぼ 1 つのテーブルごとに 2 つのテーブルを維持するという考えはあまり好きではありません (まだ可能性はあるかもしれませんが)。

「最新」ではないレコードの一貫性をチェックしないように、最初の実装を減らすことができるかもしれません。結局のところ、履歴テーブルを使用する人は、それらのテーブルに対して制約チェックを行っていないようです (同じ理由で、トリガーが必要になります)。

これについて何か考えている人はいますか?

PS - タイトルには、監査可能なデータベースについても言及されています。私が言及した前のシステムでは、常に edit_by フィールドがあります。これにより、すべての変更を追跡できるため、誰がレコードを変更したかを常に確認できました。それがどれほどの違いをもたらすかはわかりません。

ありがとう。

4

3 に答える 3

32

2011 年 1 月 1 日改訂

わかりましたので、私が座っている場所 (完全に監査可能なデータベースを提供します。あなたのデータベースはその特定の要件です) とあなたが座っている場所 (質問とコメントに基づく) の間にはギャップがあります。これについては、おそらく解説で解決します。ここからスタート地点です。

  • この要件を満たすために、次のものはまったく必要ありません。大量複製; 壊れた整合性; 等

  • これも古典的な時間要件ではないため、「期間」機能は必要ありませんが、可能です。

  • ValidFromValidTo は正規化エラーです。ValidTo は簡単に導出できるデータです。次の行の ValidFrom で、任意の行の ValidTo が複製されます。更新異常があります (ある行の 1 つの列を更新すると、次の行の他の列も更新する必要があります)。「現在」にはダミーの値を使用する必要があります。

    • すべて不要です。ValidFrom のみを使用し、データベースをクリーンで純粋な 5NF に保ちます。

    • 警告は、PostgreSQL がヒープに落ちずにサブクエリを実行できない場合 (ala Oracle)、問題なく kep ValidTo です。

これらはすべて、ユーザーがシステム内で編集可能であり、削除可能です。

うーん、ダメ。重要な情報を保持するデータベースです。スクラッチパッドではなく参照整合性を使用するため、ユーザーはそこまで歩いて何かを「削除」することはできません。これは、履歴データを維持するという同じユーザー要件 (Reading; Alert; Ack; Action; Download) と矛盾します。

  • カスケード削除は許可されていません。これらの機能は、データベース以外の MS Access タイプのチェック ボックスです。実際のデータベースの場合、RI 制約により、子を持つ親が削除されなくなります。

  • 主キーは変更できません (すべきではありません)。例えば。ユーザーID; LocationId; NetworkSlaveCode は変更されません。これらは慎重にIdentifiersと見なされることに注意してください。PK の特徴の 1 つは、安定していることです。

  • 新しいユーザーを追加できます。現在のユーザーの名前を変更できます。ただし、Download、Acknowledgement、Action にエントリがあるユーザーは削除できません。

基本的に、編集可能な場合は、履歴である必要があります (つまり、測定値とアラートは除外されます)。

また除外: ダウンロード; 謝辞; 行動。

参照テーブル: SensorType; AlertType; アクションタイプ。

新しい履歴テーブル: 挿入されますが、更新または削除することはできません。

isObselete フラグで私が見つけた問題は.. Location を変更すると、Sensor の外部キーが廃止されたレコードを指すようになり、すべてのセンサー レコードを複製する必要があるとします。この問題は、階層が大きくなるにつれて指数関数的に悪化します。

  • わかりました。では、LocationId(FK) inSensorは変更されないことを理解していますか。大量重複などはありませんか?そもそも問題はありません (そして、あのばかげた本には問題があります!) が、2 番目に指数関数的に悪化します。

  • IsObsoleteあなたの要件には不十分です。(下記参照)

  • UpdatedDtm実際の行 (などReading) は、その時点で有効だった親 (FK からSensor) の履歴行 (そのAuditedDtm) を識別します。

  • 完全なリレーショナル機能。宣言的参照整合性など

  • IDEF1X、強力な識別子の関係概念を維持します...現在の親行は1つだけです(例:場所)

  • 履歴の行は、変更前の現在の行のイメージですAuditedDtm。現在の行 (非履歴) は、行が変更された最後の UpdatedDtm を示します。

  • は、特定のキーの一連のAuditedDtm全体を示しています。UpdatedDtmsしたがって、私はそれを使用して、時間的な意味で実際のキーを「分割」しました。

必要なのは、変更可能な各テーブルの履歴テーブルだけです。4 つの識別テーブルの Hiistory テーブルを用意しました。センサー; NetworkSlave; およびユーザー。

会計の意味で Auditableを理解するために、これをお読みください。

データ・モデル

履歴を含むセンサー データ モデルへのリンク(ページ 2 には、履歴テーブルとコンテキストが含まれています)。

Relational Modeling Standard に慣れていない読者には、IDEF1X 表記法が役立つかもしれません。

コメントへの対応

(1)私の最初の問題は、履歴データとの参照整合性の問題です。存在するかどうかはわかりません。存在する場合、それがどのように機能するかはわかりません。たとえば、SensoryHistory では、場所自体が存在する前の日時を示す UpdatedDtm を持つレコードを追加することができます。これが実際に問題であるかどうかはわかりません-それを強制するのはやり過ぎかもしれません。

(他の質問でも同様の問題を提起しました。)経験したデータベースには、実際には参照整合性が設定されていなかった可能性があります。Relation 行はドキュメントのためだけに存在していたこと。RI が「アプリ コードに実装されている」こと (つまり、RI がないことを意味します)。

これは ISO/IEC/ANSI 標準 SQL データベースです。これにより、宣言的な参照整合性が可能になります。すべての関係行は、宣言された実際の制約である PK::FK 参照として実装されます。例えば:

CREATE TABLE Location
    ...
    CONSTRAINT UC_PK
        PRIMARY KEY (LocationId)
    ...
CREATE TABLE Sensor
    ...
    CONSTRAINT UC_PK
        PRIMARY KEY (LocationId, SensorNo)
    CONSTRAINT Location_Sensor_fk
        FOREIGN KEY (LocationId)
        REEFERENCES Location(LocationId)
    ...
CREATE TABLE SensorHistory
    ...
    CONSTRAINT UC_PK
        PRIMARY KEY (LocationId, SensorNo, UpdatedDtm))
    CONSTRAINT Sensor_SensorHistory_fk
        FOREIGN KEY (LocationId, SensorNo)
        REEFERENCES Sensor (LocationId, SensorNo)
    ...
これらの宣言された制約は、サーバーによって強制されます。トリガー経由ではありません。アプリコードではありません。つまり、次のことを意味します。

  • に存在しないSensora を持つAは挿入できません LocationIdLocation
  • に行がある はLocationId削除できません LocationSensor
  • に存在しないSensorHistorya を持つAは挿入できません LocationId+SensorNoSensor
  • に行がある はLocationId+SensorNo削除できません。 SensorSensorHistory

(1.1)すべての列には、値の範囲を制限するための RULE と CHECK 制約が必要です。すべての INSERT/UPDATE/DELETE がストアド プロシージャ内でプログラムによって実行されるという事実に加えて、したがって事故は発生せず、人々はデータベースに近づいてデータベースに対してコマンドを実行することはありません (SELECTS を除く)。

一般的に、私はトリガーから離れています。ストアド プロシージャと通常のアクセス許可を使用している場合は、次のようになります。

SensoryHistory では、場所自体が存在する前の日時を示す UpdatedDtm を持つレコードを追加することができます。

防止されます。センサー自体よりも前に UpdatedDtm を使用して SensorHistory を挿入することも同様です。しかし、proc は宣言型ルールではありません。ただし、二重に確実にしたい場合 (つまり、INSERTS はすべてユーザーによる直接コマンドである proc を介して行われるため)、確実にトリガーを使用する必要があります。私にとって、それは最高です。

(2)削除を示すにはどうすればよいですか? 私が推測するテーブルの非歴史的なバージョンにフラグを追加するだけで済みます。

まだ確かではない。例えば。a が削除されると最終的なものになることを受け入れますかSensor... (はい、履歴は維持されます) ... そして、新しいSensorが に追加されるとLocation、新しいものになります ...で論理的に置き換えられるSensorNoことはありませんSensor時間のギャップの有無にかかわらず、新しいもの?

エンドユーザーの観点から見ると、ソフトウェアを介して、センサーを制限なく自由に追加、編集、および削除できる必要があります。ただし、一度削除すると削除され、元に戻すことはできません。まったく同じパラメーターを使用しても、後でセンサーを再度追加するのを止めるものは何もありません。

そして「削除」Locations, NetworkSlaves、そしてUsers同様に。

Ok。次に、Sensor同じパラメーターを持つ new は真に新しく、 new を持ち、SensorNo以前の論理から独立していますSensorIsObsolete4 つの識別テーブルに BOOLEAN を追加できます。現在、適切であると識別されています。削除はソフト削除になりました。

(2.1)NetworkSensorLoggerSensorは、実際には 2 つの親に依存しています。どちらかの親が廃止された場合、それらは廃止されます。したがってIsObsolete、該当する親から派生できる二重の意味を持つ列を指定しても意味がありません。

(2.2) 明確にするために、ユーザーはトランザクション テーブルと履歴テーブルから行を削除することはできませんよね?

(3)表を更新する場合、履歴表に新しい行を挿入して主表を更新するには、どのような方法が最適ですか? トランザクション内の通常の SQL ステートメントだけでしょうか?

はい。ACID プロパティによると、これはトランザクションの古典的な使用法であり、アトミックです。toto で成功するか、toto で失敗します (後で問題が修正されたときに再試行されます)。

(4) 参考図書

決定的で影響力のあるテキストは、Temporal Data and the Relational Model CJ Date、H Darwen、NA Lorentzos です。同様に、RM を採用している私たちは、拡張機能と、RM の後継に必要なものに精通しています。他の方法ではなく。

参照された本は恐ろしく、無料です。PDF は PDF ではありません (検索なし、インデックス作成なし)。私のMSとオラクルを開くとわかります。たくさんの毛羽立ちに包まれたいくつかの良いビット。多くの虚偽表示。詳細に回答する価値はありません (適切なレビューが必要な場合は、新しい質問を開いてください)。

(4.1)ValidToに加えてValidFrom。本が犯す重大な間違い(私の回答の上部で特定されているように)。その後、苦労して解決します。そもそも間違いを犯してはいけません.2番目に解決するものは何もありません. 私が理解しているように、それはあなたのトリガーを排除します.

(4.2) 正規化と一時的な要件の両方を考慮した単純なルール。何よりもまず、(a) 一時的な要件と (b) DataTypes、正しい使用法と制限を深く理解する必要があります。常に保存:

  • DATETIME などのインスタント。更新されたDtm

  • INTEGER としての間隔。列名で Unit を明確に識別します。間隔秒

  • 限目。結合または分離に依存します。

    • この要件である結合については、(4.1) が適用されます。1 つの DATETIME を使用します。期間の終わりは、次の行の期間の開始から導き出すことができます。
    • 分離期間の場合、はい、2 x DATETIMEs が必要です。たとえば、RentedFromRentedToにギャップがあります。

(4.3) それらは「一時的な主キー」をいじり、コードを複雑にします (更新異常を制御するためのトリガーが必要になることに加えて)。私はすでにクリーンな (試行錯誤した) テンポラル主キーを提供しました。

(4.4) ダミー値、非実数値、および「現在」の Null をいじります。私はデータベースでそのようなことを許可しません。重複ValidToした を保存していないので、問題はありません。解決するものは何もありません。

(4.5) なぜ 528 ページの「テキストブック」が Web 上で無料で入手できるのか、質の悪い PDF 形式であることに疑問を抱かざるを得ません。

(5)私 [ユーザー] は、たとえば、すべての LocationHistory 行を黙って喜んで削除できます (現在のバージョンのみを Location テーブルに残します)。それが理にかなっていれば、場所。

私には意味がありません。私たちが埋めなければならないコミュニケーションにはまだギャップがあります。閉店までお付き合いください。

  • 実際の (標準 ISO/IEC/ANSI SQL) データベースでは、ユーザーに INSERT/UPDATE/DELETE パーミッションを付与しません。GRANT SELECT と REFERENCESのみ(選択したユーザーに対して) すべての INSERT/UPDATE/DELETE は、ストアド プロシージャを意味するトランザクションでコード化されます。次に、各ストアド プロシージャの GRANT EXEC を選択したユーザーに付与します (ROLES を使用して管理を軽減します)。

    • したがって、proc を実行せずにテーブルから削除することはできません。

    • 履歴テーブルから削除する proc を記述しないでください。これらの行は削除しないでください。この場合、コードの非許可と非存在が制約です。

    • 技術的には、すべての履歴行が有効であり、気にする期間はありません。最も古い LocationHistory 行には、変更前の元の Location 行の変更前イメージが含まれています。最も若い LocationHistory 行は、現在の Location 行の変更前イメージです。したがって、その間のすべての LocationHistory 行は有効であり、その間の期間に適用されます。

    • 使用されていない期間に適用されることに基づいて削除できるいくつかの LocationHistory 行を「プルーニング」または検索する必要はありません。それらはすべて使用されています。(間違いなく、それを証明するために Location の子から LocationHistory 行へのマッピングをチェックする必要はありません。)

    • 結論: ユーザーは履歴 (またはトランザクション) テーブルから削除できません。

    • それともまた違う意味ですか?

    • 上記に (1.1) を追加したことに注意してください。

(6)DMの誤字を1箇所修正。AnAlertReadingではなくの表現ですSensor

(7) それを反映するために、他の質問/回答のビジネス ルールを修正しました。そして、この質問で明らかになった新しいルール。

(8) IDEF1X に完全に準拠したモデルがあるため、識別子を再定義することを理解していますか?

  • 識別子はデータベース全体に渡され、その力を保持します。例えば。リストするときは、 and でAcknowledgements直接結合できます。中間のテーブルを読み取る必要はありません (キーが使用されている場合は読み取る必要があります)。これが、実際には、リレーショナル データベースで必要な結合が少ない (そして正規化されていないデータベースで必要な結合が多い) 理由です。LocationSensorId

  • サブタイプなどは、その特定のコンテキストが関連する場合にのみナビゲートする必要があります。

于 2011-01-01T03:51:48.480 に答える
1

私も以前にこの状況に遭遇したことがあります。追跡しようとしているデータの量によっては、困難な場合があります。履歴テーブルは、履歴テーブルのレコードの「スナップショット」を取得し、必要に応じて運用テーブルに変更を加えることができるため、使いやすい場合があります。実装は非常に簡単ですが、データの量と変更頻度によっては、非常に大きな履歴テーブルが作成される可能性があります。

別のオプションは、誰かが何が起こったかを「再生」して追跡できるようにするすべての変更をログに記録することです。各変更はテーブルまたはフィールド (必要に応じて) に記録され、誰が、いつ、何が何に変更されたかを追跡します。つまり、2010 年 12 月 31 日に Bob がステータスを「オープン」から「クローズ」に変更しました。

どのシステムを使用するかは、通常、データを後でどのように保持/確認/使用する必要があるかによって異なります。自動化されたレポート、人によるレビュー、2 つの組み合わせなど。

于 2010-12-20T16:23:24.620 に答える
0

予算や環境によっては、Oracle のフラッシュバック アーカイブ機能の使用を検討することをお勧めします。

テーブル内の行の自動「アーカイブ」をオンにしてから、次のようなものを使用してベーステーブルでステートメントを実行できます

選択する *
FROM 重要データ
AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '5' DAY)

Oracle は、別の (シャドウ) テーブルに履歴を保持します。結合を使用してクエリを実行できるように、任意のテーブルに対してこれを実行できます。

于 2010-12-21T13:10:34.770 に答える