[database-design] 감사 로깅을위한 데이터베이스 디자인

새 데이터베이스를 디자인해야 할 때마다 변경 사항에 대한 감사 로그를 유지하기 위해 데이터베이스 스키마를 설정하는 방법에 대해 꽤 많은 시간을 할애합니다.

여기에 대해 이미 몇 가지 질문이 있었지만 모든 시나리오에 대해 최선의 단일 접근법이 있다는 것에 동의하지 않습니다.

또한 각 접근 방식의 장단점을 나열하는 데이터베이스 변경 로그 유지 관리에 대한흥미로운 기사를 우연히 발견했습니다 . 잘 작성되어 있고 흥미로운 정보가 있지만 내 결정을 더 어렵게 만들었습니다.

내 질문은 : 내가 사용할 수있는 참조가 있습니까, 책이나 의사 결정 트리와 같은 일부 입력 변수를 기반으로 어떤 방법으로 결정 해야하는지 결정할 수 있습니까?

  • 데이터베이스 스키마의 성숙
  • 로그를 쿼리하는 방법
  • 레코드를 다시 작성해야 할 확률
  • 더 중요한 것 : 쓰기 또는 읽기 성능
  • 기록되는 값의 특성 (문자열, 숫자, 얼룩)
  • 사용 가능한 저장 공간

내가 아는 접근법은 다음과 같습니다.

1. 생성 및 수정 된 날짜 및 사용자에 대한 열 추가

테이블 예 :

  • 신분증
  • value_1
  • value_2
  • value_3
  • created_date
  • modified_date
  • created_by
  • modified_by

주요 단점 : 우리는 수정의 역사를 잃습니다. 커밋 후 롤백 할 수 없습니다.

2. 테이블 만 삽입

테이블 예 :

  • 신분증
  • value_1
  • value_2
  • value_3
  • …에서
  • 삭제됨 (부울)
  • 사용자

주요 단점 : 외래 키를 최신 상태로 유지하는 방법은 무엇입니까? 필요한 큰 공간

3. 각 테이블에 대해 별도의 히스토리 테이블 작성

히스토리 테이블 예 :

  • 신분증
  • value_1
  • value_2
  • value_3
  • value_4
  • 사용자
  • 삭제됨 (부울)
  • 타임 스탬프

주요 단점 : 모든 감사 된 테이블을 복제해야합니다. 스키마가 변경되면 모든 로그도 마이그레이션해야합니다.

4. 모든 테이블에 대한 통합 히스토리 테이블 작성

히스토리 테이블 예 :

  • table_name
  • 사용자
  • new_value
  • 삭제됨 (부울)
  • 타임 스탬프

주요 단점 : 필요한 경우 레코드 (롤백)를 쉽게 다시 만들 수 있습니까? new_value 열은 거대한 문자열이어야하므로 다른 모든 열 유형을 지원할 수 있습니다.



답변

몇몇 위키 플랫폼에서 사용하는 한 가지 방법은 식별하는 데이터와 감사하는 컨텐츠를 분리하는 것입니다. 복잡성을 추가하지만 편집 한 필드 목록뿐만 아니라 사용자에게 이전 레코드의 모양에 대한 정보를 제공하기 위해 매쉬업해야하는 완전한 레코드의 감사 추적으로 끝납니다.

예를 들어 영업 거래를 추적 할 수있는 기회 라는 테이블이있는 경우 실제로 두 개의 별도 테이블을 작성합니다.

기회
기회 _ 콘텐츠 (또는 이와 유사한 것)

기회 표는 고유 레코드를 식별하는 데 사용하는 것입니다 당신이 당신의 외래 키 관계를 참조하려는 기본 키를 수용 할 정보가있을 것입니다. 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 및 개정의 다중 열 키로 만들고 개정이 ID 유형 인 경우 수정합니다. 개정 열을 FK로 사용합니다. 그런 다음 다음과 같이 JOINing하여 통합 레코드를 가져옵니다.

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

거기에 약간의 오류가있을 수 있습니다 … 이것은 내 머리 꼭대기에 있습니다. 그러나 대체 패턴에 대한 아이디어를 제공해야합니다.


답변

SQL Server 2008을 사용하는 경우 변경 데이터 캡처를 고려해야합니다. 이것은 2008 년에 새로 도입되었으며 상당한 양의 작업을 절약 할 수 있습니다.


답변

나는 어떤 참조도 모르지만 누군가 무언가를 썼을 것이라고 확신한다.

그러나 목적이 단순히 감사 로그를 가장 일반적으로 사용하는 상황을 기록하는 것만으로 모든 것을 유지하지 않는 이유는 무엇입니까?

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

아마도 이것은 트리거에 의해 유지됩니다.


답변

블로깅 애플리케이션을위한 작은 예제 데이터베이스를 작성합니다. 두 개의 테이블이 필요합니다.

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;


답변

의사 결정 트리와 같은 것은 없다고 생각합니다. 장단점 (또는 요구 사항) 중 일부는 실제로 계산할 수 없기 때문에. 예를 들어 성숙도를 어떻게 측정합니까?

감사 로깅에 대한 비즈니스 요구 사항을 정렬하십시오. 이러한 요구 사항이 향후 어떻게 변경 될지 예측하고 기술 요구 사항을 생성하십시오. 이제 장단점과 비교하여 올바른 / 최상의 옵션을 선택할 수 있습니다.

그리고 당신이 어떻게 결정하든 상관없이, 당신이 항상 잘못 결정했다고 생각하는 사람이있을 것입니다. 그러나, 당신은 숙제를하고 결정을 정당화합니다.


답변