4

DB2 の多数のテーブルでフィールドの変更を追跡するための履歴テーブルを作成したいと考えています。

履歴は通常、テーブルの構造全体をコピーして接尾辞付きの名前を付けることで行われることを知っています (例: user --> user_history)。次に、非常に単純なトリガーを使用して、UPDATE で古いレコードを履歴テーブルにコピーできます。

ただし、私のアプリケーションでは、これはあまりにも多くのスペースを使用します。フィールドが変更されるたびに、レコード全体を別のテーブルにコピーするのは (少なくとも私には) 良い考えとは思えません。したがって、個々のフィールドの変更を追跡する一般的な「履歴」テーブルを作成できると考えました。

CREATE TABLE history
(
    history_id LONG GENERATED ALWAYS AS IDENTITY,
    record_id INTEGER NOT NULL,
    table_name VARCHAR(32) NOT NULL,
    field_name VARCHAR(64) NOT NULL,
    field_value VARCHAR(1024),
    change_time TIMESTAMP,
    PRIMARY KEY (history_id)
);

追跡したいすべてのテーブルには、自動生成された単一の id フィールドが主キーとしてあり、これは「record_id」フィールドに入れられます。また、テーブル内の VARCHAR の最大サイズは 1024 です。明らかに、VARCHAR 以外のフィールドが変更された場合は、レコードを履歴テーブルに挿入する前に VARCHAR に変換する必要があります。

さて、これは物事を行うための完全に遅れた方法かもしれません (ねえ、もしそうなら理由を教えてください)。時間の長さ。

とにかく、更新時に履歴テーブルにレコードを追加するトリガーを作成するのに助けが必要です。たとえば、架空のユーザー テーブルを考えてみましょう。

CREATE TABLE user
(
   user_id INTEGER GENERATED ALWAYS AS IDENTITY,
   username VARCHAR(32) NOT NULL,
   first_name VARCHAR(64) NOT NULL,
   last_name VARCHAR(64) NOT NULL,
   email_address VARCHAR(256) NOT NULL
   PRIMARY KEY(user_id)
);

それで、変更を履歴テーブルに挿入するために、ユーザーテーブルの更新時にトリガーを手伝ってくれる人はいますか? 私の推測では、手続き型 SQL を使用して古いレコードのフィールドをループし、それらを新しいレコードのフィールドと比較し、一致しない場合は履歴テーブルに新しいエントリを追加する必要があると思います。

可能であれば、フィールドに関係なく、すべてのテーブルに同じトリガー アクション SQL を使用することをお勧めします。

ありがとう!

4

4 に答える 4

1

これを 2 段階のプロセスとして考えたことはありますか? 行全体の元のバージョンと変更されたバージョンを記録する単純なトリガーを実装します。次に、上記のように、変更されたフィールドを抽出するために 1 日 1 回実行される別のプログラムを作成します。

これにより、トリガーがよりシンプル、安全、高速になり、後処理ステップを実装する方法の選択肢が増えます。

于 2008-11-11T16:42:34.737 に答える
1
CREATE TABLE HIST.TB_HISTORY ( 
    HIST_ID     BIGINT GENERATED ALWAYS AS IDENTITY (START WITH 0, INCREMENT BY 1, NO CACHE) NOT NULL,
    HIST_COLUMNNAME     VARCHAR(128) NOT NULL,
    HIST_OLDVALUE       VARCHAR(255),
    HIST_NEWVALUE       VARCHAR(255),
    HIST_CHANGEDDATE    TIMESTAMP NOT NULL
    PRIMARY KEY(HIST_SAFTYNO)
)
GO


CREATE TRIGGER COMMON.TG_BANKCODE AFTER
UPDATE OF FRD_BANKCODE ON COMMON.TB_MAINTENANCE
REFERENCING OLD AS oldcol NEW AS newcol FOR EACH ROW MODE DB2SQL
WHEN(COALESCE(newcol.FRD_BANKCODE,'#null#') <> COALESCE(oldcol.FRD_BANKCODE,'#null#'))
BEGIN ATOMIC

    CALL FB_CHECKING.SP_FRAUDHISTORY_ON_DATACHANGED(
                newcol.FRD_FRAUDID,
                'FRD_BANKCODE',
                oldcol.FRD_BANKCODE,
                newcol.FRD_BANKCODE,
                newcol.FRD_UPDATEDBY
    );--

    INSERT INTO FB_CHECKING.TB_FRAUDMAINHISTORY(        
        HIST_COLUMNNAME, 
        HIST_OLDVALUE, 
        HIST_NEWVALUE, 
        HIST_CHANGEDDATE
于 2008-11-14T01:40:39.060 に答える
1

SQL Server データベースでも同様のことを行いますが、監査テーブルは監査対象の個々のテーブルごとに作成されます (データベースのサイズが何ギガバイトもあるため、1 つの中央テーブルは非常に大きくなります)。

必要なことの 1 つは、誰が変更を行ったかを記録することです。また、古い値と新しい値を一緒に記録し (必要に応じてデータを簡単に元に戻すことができるようにします)、変更の種類 (挿入、更新、削除) も記録する必要があります。テーブルからの削除の記録については言及されていませんが、これらは、テーブルを最も頻繁に使用する目的の一部であることがわかります。

動的 SQl を使用して監査テーブルを作成するコードを生成し (システム情報を格納するテーブルを使用して)、すべての監査テーブルはまったく同じ構造を持ちます (データを簡単に取得できます)。

履歴テーブルにデータを保存するコードを作成するときに、必要に応じてデータを復元するためのコードも作成します。これにより、何かを復元する必要があり、上級管理職から今すぐそれを完了するよう圧力をかけられている場合に、時間を大幅に節約できます。

履歴テーブルからデータを復元できるようにする計画があったかどうかはわかりませんが、一度復元できれば、経営陣がそのように使用することを望んでいると確信できます.

于 2008-11-11T19:08:27.517 に答える
1

複数の値が変更される大きなテーブルでは、値ごとにさらに多くのオーバーヘッドが発生するため、これは良い考えではないと思います。ただし、それはアプリケーションによって異なります。

さらに、そのような履歴テーブルの実用的な価値を考慮する必要があります。変更された値のコンテキストを垣間見るだけでも、多くの行をまとめる必要があり、エンドユーザー向けにこの複雑な履歴ロジックを実行する別のアプリケーションをコーディングする必要があります。また、DB 管理者にとって、履歴から値を復元するのは面倒です。

少し厳しいように聞こえるかもしれませんが、それは意図したものではありません。当店の経験豊富なプログラマーは、テーブル ジャーナリングを通じて同様のアイデアを思いつきました。彼はそれを起動して実行しましたが、明日がないかのようにディスク容量を消費しました。

履歴テーブルが実際に何を達成すべきかを考えてみてください。

于 2008-11-11T07:42:16.717 に答える