web-dev-qa-db-ja.com

監査ログのデータベース設計

新しいデータベースを設計する必要があるたびに、変更の監査ログを保持するためにデータベーススキーマをどのように設定するかについてかなりの時間を費やしています。

これについてはすでにいくつかの質問が出されていますが、すべてのシナリオに最適なアプローチが1つしかないことに同意しません。

また、私はこれにつまずきました データベース変更のログの管理に関する興味深い記事 各アプローチの長所と短所をリストしようとしています。非常によく書かれており、興味深い情報を持っていますが、私の決定をさらに難しくしました。

私の質問は次のとおりです:私が使用できるリファレンスはありますか、本や私が参照することができる決定ツリーのようなものがありますか?次のようないくつかの入力変数に基づいて進みます。

  • データベーススキーマの成熟度
  • ログのクエリ方法
  • レコードを再作成する必要がある確率
  • さらに重要なこと:書き込みまたは読み取りのパフォーマンス
  • ログに記録される値の性質(文字列、数値、ブロブ)
  • 利用可能なストレージスペース

私が知っているアプローチは次のとおりです。

1。作成日および変更日とユーザーの列を追加します

テーブルの例:

  • id
  • value_1
  • value_2
  • value_3
  • 作成日
  • 変更日
  • によって作成された
  • によって変更

主な短所:変更の履歴が失われます。コミット後にロールバックできません。

2。テーブルのみを挿入

テーブルの例

  • id
  • value_1
  • value_2
  • value_3
  • から
  • 削除(ブール値)
  • ユーザー

主な短所:外部キーを最新の状態に保つ方法は?巨大なスペースが必要

3。各テーブルに個別の履歴テーブルを作成します

履歴テーブルの例:

  • id
  • value_1
  • value_2
  • value_3
  • value_4
  • ユーザー
  • 削除(ブール)
  • タイムスタンプ

主な短所:すべての監査対象テーブルを複製する必要があります。スキーマが変更された場合、すべてのログも移行する必要があります。

4。すべてのテーブルの統合履歴テーブルを作成します

履歴テーブルの例:

  • テーブル名
  • フィールド
  • ユーザー
  • new_value
  • 削除(ブール値)
  • タイムスタンプ

主な短所:必要に応じて簡単にレコードを再作成(ロールバック)できますか? new_value列は、すべての異なる列タイプをサポートできるように、巨大な文字列である必要があります。

140
jbochi

いくつかのウィキプラットフォームで使用されている1つの方法は、識別データと監査対象のコンテンツを分離することです。これにより複雑さが増しますが、編集されたフィールドのリストだけでなく、完全なレコードの監査証跡になります。編集したフィールドをマッシュアップして、古いレコードがどのように見えるかをユーザーに知らせる必要があります。

たとえば、販売取引を追跡するOpportunitiesというテーブルがある場合、実際には2つの個別のテーブルを作成します。

機会
Opportunities_Content(またはそのようなもの)

Opportunitiesテーブルには、レコードを一意に識別するために使用する情報があり、外部キー関係のために参照するプライマリキーを格納します。 Opportunities_Contentテーブルには、ユーザーが変更でき、監査証跡を保持したいすべてのフィールドが保持されます。 Contentテーブルの各レコードには、独自のPKと、変更日および変更日データが含まれます。 Opportunitiesテーブルには、現在のバージョンへの参照と、メインレコードがいつ誰によって作成されたかに関する情報が含まれます。

以下に簡単な例を示します。

CREATE TABLE dbo.Page(  
    ID int PRIMARY KEY,  
    Name nvarchar(200) NOT NULL,  
    CreatedByName nvarchar(100) NOT NULL, 
    CurrentRevision int NOT NULL, 
    CreatedDateTime datetime NOT NULL

そして内容:

CREATE TABLE dbo.PageContent(
    PageID int NOT NULL,
    Revision int NOT NULL,
    Title nvarchar(200) NOT NULL,
    User nvarchar(100) NOT NULL,
    LastModified datetime NOT NULL,
    Comment nvarchar(300) NULL,
    Content nvarchar(max) NOT NULL,
    Description nvarchar(200) NULL

RevisionがIDタイプである場合、ContentsテーブルのPKをPageIDとRevisionからの複数列キーにすることになるでしょう。リビジョン列をFKとして使用します。次に、次のように参加して統合レコードを取得します。

SELECT * FROM Page
JOIN PageContent ON CurrentRevision = Revision AND ID = PageID

そこにいくつかのエラーがあるかもしれません...これは私の頭の外です。ただし、代替パターンのアイデアが得られるはずです。

81
Josh Anderson

SQL Server 2008を使用している場合は、おそらく変更データキャプチャを検討する必要があります。これは2008年の新機能であり、作業量を大幅に節約できます。

13
Randy Minder

参考文献は知りませんが、誰かが何かを書いたと確信しています。

ただし、目的が単に、何が起こったのかを記録すること(監査ログの最も一般的な使用)である場合、単純にすべてを保持しないのはなぜですか。

timestamp
username
ip_address
procedureName (if called from a stored procedure)
database
table
field
accesstype (insert, delete, modify)
oldvalue
newvalue

おそらくこれはトリガーによって維持されます。

6
wallyk

ブログアプリケーション用の小さなサンプルデータベースを作成します。 2つのテーブルが必要です。

blog:一意の投稿ID、タイトル、コンテンツ、および削除済みフラグを保存します。 audit:レコードID、ブログ投稿ID、変更タイプ(NEW、EDITまたはDELETE)およびその変更の日付/時刻とともに、履歴変更の基本セットを保存します。次のSQLはblogを作成し、削除された列にインデックスを付けます。

CREATE TABLE `blog` (
    `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
    `title` text,
    `content` text,
    `deleted` tinyint(1) unsigned NOT NULL DEFAULT '0',
    PRIMARY KEY (`id`),
    KEY `ix_deleted` (`deleted`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='Blog posts';

次のSQLはauditテーブルを作成します。すべての列にインデックスが付けられ、blog.idを参照するaudit.blog_idの外部キーが定義されます。したがって、ブログエントリを物理的に削除すると、完全な監査履歴も削除されます。

CREATE TABLE `audit` (
    `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
    `blog_id` mediumint(8) unsigned NOT NULL,
    `changetype` enum('NEW','EDIT','DELETE') NOT NULL,
    `changetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `ix_blog_id` (`blog_id`),
    KEY `ix_changetype` (`changetype`),
    KEY `ix_changetime` (`changetime`),
    CONSTRAINT `FK_audit_blog_id` FOREIGN KEY (`blog_id`) REFERENCES `blog` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
3
ajit

決定木のようなものは何もないと思います。長所と短所(または要件)の一部は実際には数えられないためです。たとえば、成熟度をどのように測定しますか?

したがって、監査ログのビジネス要件を揃えてください。これらの要件が将来どのように変化するかを予測し、技術要件を生成してください。今、あなたはそれを賛否両論と比較し、正しい/最良のオプションを選択することができます。

そして、あなたがどのように決定するかは問題ではありません。あなたが間違った決定をしたと思う人が必ずいるでしょう。しかし、あなたは宿題をし、あなたの決定を正当化します。

2
Peter Schuetze