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


151

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

これについてはすでにいくつかの質問がここで行われていますが、すべてのシナリオに単一の最良のアプローチがあることに同意しません。

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

私の質問は、私が使用できる参照、おそらく本や決定木のようなものであり、いくつかの入力変数に基づいてどの方向に進むべきかを決定するために参照できますか?

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

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

1.作成および変更された日付とユーザーの列を追加する

テーブルの例:

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

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

2.テーブルのみを挿入する

表の例

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

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

3.テーブルごとに個別の履歴テーブルを作成する

履歴テーブルの例:

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

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

4.すべてのテーブルの統合履歴テーブルを作成する

履歴テーブルの例:

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

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



1
そして、テーブルの代わりに履歴データベースを使用するのはどうですか?
Jowen


実行されたすべての(必要な)クエリをそのまま記録するのは悪い考えですか?
Dinushan

回答:


87

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

したがって、たとえば、商談を追跡するOpportunitiesというテーブルがある場合、実際には2つの別々のテーブルを作成します。

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

機会表には、レコードを一意に識別するために使用したいとあなたが外部キーの関係のために参照したい主キーを収容しまうの情報を持っているでしょう。Opportunities_Contentのテーブルには、ユーザーが変更することができ、すべてのフィールドを保持するだろうし、そのためにあなたは、監査証跡を維持したいと思います。Contentテーブルの各レコードには、独自のPKと、変更者および変更日データが含まれます。機会の表は、現在のバージョンを参照するだけでなく、メインのレコードが最初に作成されたときに誰によって情報が含まれます。

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

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

おそらくコンテンツテーブルのPKをPageIDからの複数列のキーにし、RevisionがIDタイプである場合はRevisionにします。リビジョン列をFKとして使用します。次に、次のようにJOINingして統合レコードをプルします。

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

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


10
監査には優れたアプローチですが、本番環境では、データベース内のテーブルごとに個別の監査テーブルを開発し、変更をキャプチャするための各テーブルのトリガーを作成して監査テーブルに書き込むには、かなりの時間がかかります。さらに、各監査テーブルは構造が異なるため、すべてのテーブルについて単一の監査レポートを作成することは非常に困難です。
asim-ishaq 2013年

11
各テーブルのスクリプトの作成と保守が監査対象のデータベースを管理しようとする組織にとって懸念事項である場合は、経験豊富なDBA、または監査対象データベースの作成に十分な経験を持つ非常に柔軟で非常に経験豊富なソフトウェアエンジニアを雇うことをお勧めします。
Hardryv 2015

1
それはそれが正しいことPageContent.PageIDにFKをあるPage.IDPage.CurrentRevisionFKがにありますかPageContent.Revision?この依存関係は本当に循環していますか?

2
言及されている代替案に対応していないため、私は反対票を投じました。これは、非常に特定のユースケースに対する非常に特定のソリューションである別のオプションを提供します。しかし、私は提案された設計のメリットを見ています
アクテオン

1
確信を持って言えるフィールドはほとんど変わらないと考えることができるので、各エンティティのすべての「メイン」テーブルは最終的にはそのままになりid, revision_idます。ジャンクションテーブルの詳細です。これは少しにおいがします。これは、OPのアプローチ3(監査済みテーブルごとの履歴テーブル)に対してどのような利点がありますか?
ケンモア2018年

14

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


SQL 2012の変更追跡情報へのリンクは次のとおりです。msdn.microsoft.com/en-us/library/bb933994.aspx +1組み込み機能を使用するための+1で、ホイールを再発明する意味がありません。
Chris

4
@クリスは自分で使ったことがありますか?確かに、それはすべてを追跡します...しかし、そこから有用な情報を得ることができることは、まったく別の話です。自転車にトラクターの車輪を使用できません。
Jowen

これは本当に素晴らしかったでしょう。しかし、SQL ServerのStandardエディションしか持っていない場合、私と同じように、「変更データキャプチャはEnterpriseDeveloper、およびEnterprise Evaluationエディションでのみ利用できます」とは言えません。
Brad Turek

6

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

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

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

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


データベースサーバー内でそれを取得する方法はわかりませんが、もちろん、それを外部から簡単に行うことができます。
wallyk

5
これは、元の質問で示した4番目のオプションと同じデザインパターンのようです。
givanse

3

ブログアプリケーション用の小さなサンプルデータベースを作成します。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;

2

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

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.