22

Codeigniter を使用してシステムを作成し、MySQL を使用してデータベースとして作成しました。システムには、さまざまな権限を持つユーザー、ユーザーグループなどがあります。多対多の関係を持つ多数のmysqlテーブルがあります。

私が持っているテーブルのいくつか:

  • アイテム
  • 契約
  • 顧客
  • 製品
  • 製品の特徴
  • 注文
  • order_features
  • order_products
  • 等...

現在、ユーザーが行ったこれらのテーブルのデータのすべての変更をログに記録しています。ユーザーは、権限によりこれらのデータを変更できます。次のような単純な形式のみのログの変更を保存する

A user changed product features with id of A8767
B user added new customer with id 56
C user edited content of orderlist
A user added new product (id: A8767) to order (id: or67)
...

質問Stackoverflowの編集履歴など、細部にまで加えたすべての変更を保持したい。log_tableさまざまなテーブルからのすべてのデータ変更を保持するための設計を考えることができます。それを行う方法、チュートリアル、エンジン、プラグインはありますか? すべてのテーブルを複製して変更を保存し続けるとは思えませんが、それが良い方法だとは思いません。

4

2 に答える 2

23

私はそれについてしばらく考えていましたが、これを行うには2つの方法しか考えられません。どちらも、抽象データレイヤー/モデルに作成すると完全に透過的に機能します。

ちなみに、ORMマッパーの教義には「バージョン管理可能な」テーブルデータの実装があります。ドキュメントでこの例を参照してください。たぶんそれはあなたのニーズに合っていますが、私のものには合いません。元のレコードが削除されると、すべての履歴データが削除されるように見えるため、実際にはリビジョンセーフではありません。

オプションA:リビジョンデータを保持するために各テーブルのコピーを用意する

簡単な連絡先テーブルがあるとしましょう。

CREATE TABLE contact (
    id INT NOT NULL auto_increment,
    name VARCHAR(255),
    firstname VARCHAR(255),
    lastname VARCHAR(255),
    PRIMARY KEY (id)
)

そのテーブルのコピーを作成し、リビジョンデータを追加します。

CREATE TABLE contact_revisions (
    id INT NOT NULL,
    name VARCHAR(255),
    firstname VARCHAR(255),
    lastname VARCHAR(255),
    revision_id INT auto_increment,
    type ENUM('INSERT', 'UPDATE', 'DELETE') NOT NULL,
    change_time DEFAULT current_timestamp,
    PRIMARY KEY(revision_id)
)

トリガーを追跡しINSERTUPDATE使用します。AFTERオリジナルの新しいデータリビジョンごとに、新しいデータのコピーをリビジョンテーブルに挿入し、変更をtype適切に設定します。

リビジョンセーフをログに記録するDELETEには、履歴テーブルに新しい行も挿入する必要があります。このためには、BEFORE DELETEトリガーを使用して、削除する前に最新の値を保存する必要があります。それ以外の場合は、履歴テーブルのすべてNOT NULLの制約も削除する必要があります。

この実装に関するいくつかの重要な注意事項

  • 履歴テーブルの場合、データリビジョンごとに同じキーが複数回あるため、リビジョンテーブルからすべてUNIQUE KEY(ここでは:)を削除する必要があります。PRIMARY KEY
  • ALTER更新(ソフトウェア更新など)を介して元のテーブルのスキーマとデータを取得する場合は、履歴テーブルとそのデータにも同じデータまたはスキーマ修正が適用されていることを確認する必要があります。そうしないと、レコードセットの古いリビジョンに戻すときに問題が発生します。
  • 実際の実装では、どのユーザーがデータを変更したかを知りたいと思うでしょう。その改訂を安全にするために、ユーザーレコードをusersテーブルから削除しないでください。アカウントをフラグで無効に設定する必要があります。
  • 通常、単一のユーザーアクションには複数のテーブルが含まれます。実際の実装では、複数のテーブルのどの変更が単一のユーザートランザクションに属し、どの順序で行われるかも追跡する必要があります。実際のユースケースでは、1つのトランザクションのすべての変更を逆の順序で一緒に元に戻す必要があります。これには、ユーザーとトランザクションを追跡し、履歴テーブル内のすべての個々のリビジョンとのゆるい関係を保持する追加のリビジョンテーブルが必要になります。

利点:

  • アプリケーションコードから独立して、完全にデータベースにあります。(ユーザートランザクションの追跡が重要な場合はそうではありません。単一のクエリの範囲外のロジックが必要になります)
  • すべてのデータは元の形式であり、暗黙的な型変換はありません。
  • リビジョンでの検索で良好なパフォーマンス
  • 簡単なロールバック。INSERT .. ON DUPLICATE KEY UPDATE ..ロールバックするリビジョンのデータを使用して、元のテーブルで簡単なステートメントを実行するだけです。

メリット:

  • 手動で実装するのは難しい。
  • データベースの移行/アプリケーションの更新に関しては、自動化するのは困難です(不可能ではありません)。

すでに上で述べたように、教義versionableは似たようなことをします。


オプションB:中央の変更ログテーブルを用意する

序文:悪い習慣、代替案の説明のためにのみ示されています。

このアプローチは、データレイヤー/モデルに隠されている必要があるアプリケーションロジックに大きく依存しています。

あなたは追跡し続ける中央の履歴テーブルを持っています

  • 誰がした
  • いつ
  • 変更、挿入、または削除
  • どのデータ
  • どの分野で
  • どのテーブルの

他のアプローチと同様に、どの個々のデータ変更が単一のユーザーアクション/トランザクションに属し、どの順序であるかを追跡することもできます。

利点:

  • テーブルにフィールドを追加したり、新しいテーブルを作成したりするときに、元のテーブルと同期を保つ必要はありません。透過的にスケーリングします。

メリット:

  • 単純な値を使用する悪い習慣=データベースのキーストア
  • 暗黙的な型変換のため、検索パフォーマンスが悪い
  • 書き込みロックが原因で中央履歴テーブルがボトルネックになると、アプリケーション/データベースの全体的なパフォーマンスが低下する可能性があります(これは、テーブルロックを備えた特定のエンジン(MyISAMなど)にのみ適用されます)
  • ロールバックを実装するのははるかに困難です
  • 暗黙の型変換によるデータ変換エラー/精度の低下の可能性
  • モデル/データレイヤーを使用する代わりに、コードのどこかでデータベースに直接アクセスする場合、変更を追跡しません。この場合、リビジョンログに手動で書き込む必要があることを忘れてください。他のプログラマーとチームで作業する場合、大きな問題になる可能性があります。

結論:

  • オプションBは、変更をログに記録するためだけの単純な「ドロップイン」として、小さなアプリに非常に便利です。
  • 過去にさかのぼって、過去のリビジョン123とリビジョン125の違いを簡単に比較したり、古いデータに戻したりしたい場合は、オプションAを使用するのは難しい方法です。
于 2012-03-24T22:58:57.587 に答える
2

一般的なユニ更新テーブルの使用はどうですか。テーブル フィールドは次の値を保持する必要があります。

user,event,date,table,field,new value

  • user - 誰が変更したか
  • event - 定義済みイベントのコードとして (更新、保存、挿入)
  • date - 変更が行われた日時
  • テーブルとフィールド - グローバル クエリから自動ローカライズ可能
  • 値 - 挿入された値

値と挿入は、一般的なクエリからいくつかの関数で作成できます。

于 2012-03-24T22:45:13.780 に答える