데이터베이스에서 행의 모든 ​​변경 사항을 기록하면 일반적으로 어떻게 저장됩니까?


10

내가 작업중 인 프로젝트 에서 데이터베이스의 일부 테이블에있는 행의 모든 ​​변경 사항 은 추가 감사 또는 롤백을 위해 추적되어야합니다 . 누가 IP 주소와 시간에서 행을 수정했는지 쉽게 찾고 이전 버전을 복원 할 수 있어야합니다.

비슷한 것은 예를 들어 Stack Exchange에서 사용됩니다. 다른 사람의 질문을 변경하면 내가 변경 한 것을 발견하고 변경 사항을 롤백 할 수 있습니다.

현재 스키마에 평균 비즈니스 앱과 거의 동일한 속성 (아래)이 있다고 가정 할 때 데이터베이스의 객체에 대한 모든 변경 사항을 저장하는 데 사용되는 일반적인 기술은 무엇입니까 ?

  • 몇 가지가있을 수 있습니다 : 개체는 상대적으로 작은 크기를 가지고 nvarchar(1000)예를 들어,하지만 이진 데이터의 거대한 모양은,이 직접, 직접 디스크에 저장하고, 액세스하지 하지 마이크로 소프트 SQL을 통해 filestream,
  • 데이터베이스로드는 매우 낮으며 전체 데이터베이스는 서버에서 하나의 가상 머신으로 처리됩니다.
  • 이전 버전에 대한 액세스는 최신 버전에 대한 액세스만큼 빠를 필요는 없지만 여전히 최신 ¹이어야하고 너무 느리지 않아야합니다 ².

<tl-dr>

나는 다음과 같은 경우에 대해 생각했지만 그러한 시나리오에 대한 실제 경험이 없으므로 다른 사람들의 의견을들을 것입니다.

  1. ID와 버전으로 행을 구별하여 모든 것을 동일한 테이블에 저장하십시오. IMO는 매우 어리 석고 조만간 성능 수준이 떨어질 것입니다. 이 방법을 사용하면 최신 항목 및 버전 추적에 다른 보안 수준을 설정할 수도 없습니다. 마지막으로 모든 쿼리는 작성하기가 더 복잡합니다. 실제로 최신 데이터에 액세스하려면 ID로 모든 것을 그룹화하고 각 그룹에서 마지막 버전을 검색해야합니다.

  2. 한 테이블에 최신 버전을 저장하고, 변경 될 때마다 더 이상 사용되지 않는 버전을 다른 스키마의 다른 테이블로 복사하십시오. 결함은 매번 변화하지 않더라도 모든 가치를 저장한다는 것입니다. 변경되지 않은 값을 null로 설정 하는 것은 해결책이 아닙니다. 값이 언제 null또는로 변경되는지 추적해야하기 때문 입니다 null.

  3. 한 테이블에 최신 버전을 저장하고 변경된 값 목록을 이전 값과 함께 다른 테이블에 저장하십시오. 두 가지 결함이있는 것 같습니다. 가장 중요한 방법은 동일한 열에서 이기종 유형의 이전 값을 정렬하는 유일한 방법은을 갖는 것 binary(max)입니다. 두 번째는 이전 버전을 사용자에게 표시 할 때 그러한 구조를 사용하는 것이 더 어렵다는 것입니다.

  4. 이전 두 지점에서와 동일한 작업을 수행하지만 버전을 별도의 데이터베이스에 저장하십시오. 성능 측면에서 볼 때 동일한 데이터베이스에 이전 버전이 있으면 최신 버전에 대한 액세스 속도가 저하되는 것을 피할 수 있습니다. 여전히, 나는 그것이 조기 최적화이며 동일한 데이터베이스에 이전 및 최신 버전이 병목 현상이 있다는 증거가있는 경우에만 수행해야한다고 생각합니다.

</ tl-dr>


¹ 예를 들어, HTTP 로그에 대해 수행 된대로 변경 사항을 로그 파일에 저장하고 서버로드가 가장 적은 밤에 로그에서 데이터베이스로 데이터를 플러시 할 수 없습니다. 다른 버전에 대한 정보는 즉시 또는 거의 즉시 사용 가능해야합니다. 몇 초 지연이 허용됩니다.

²이 정보는 특정 사용자 그룹에 의해서만 자주 액세스되지는 않지만 버전 목록이 표시 될 때까지 30 초 동안 기다리도록 허용 할 수 없습니다. 다시, 몇 초 지연이 허용됩니다.


3
관련 : SQL Server 변경 데이터 캡처 .
Nick Chammas

답변:


8

이러한 종류의 감사 로깅을 수행하는 일반적인 방법은 섀도우 테이블을 사용하고 감사하는 기본 테이블에서 트리거를 사용하여 변경 사항을 기록하는 것입니다. 성능을 위해 필요한 경우 다른 테이블을 다른 물리 디스크에 배치 할 수 있으며, 빠른 데이터 검색을 지원해야하는 경우 인덱스를 추가 할 수 있습니다.

테이블은 원래 테이블과 거의 동일한 구조를 갖지만 변경이 발생한 날짜와 시간, 행 삽입, 변경 또는 삭제 여부에 대한 마커가 있습니다. 타임 스탬프를 통해 버전 순서를 지정할 수 있습니다.

변경 날짜는 디폴트 getdate ()를 사용하여 datetime 열을 널 (null)로 만들지 않고 수행 할 수 있습니다. 감사 사용자 열은 널이 아닌 열이 기본값 인 Suser_Sname ()으로 사용자를 캡처합니다. 실제 사용자가 세션에서 가장되고 있다고 가정하면 변경하는 사용자의 신원이 캡처됩니다.

데이터베이스는 웹 서버에 연결하는 IP 주소를 알 수있는 방법이 없습니다. 애플리케이션은 트랜잭션으로 IP 주소를 명시 적으로 캡처하고 기록해야합니다.

감사 할 테이블이 많은 경우 시스템 데이터 사전의 메타 데이터를 사용하여 프로그래밍 방식으로 트리거를 생성 할 수 있습니다.

이 솔루션은 여러 가지 이유로 가장 좋습니다.

  • 응용 프로그램에서 작성된 변경 사항뿐만 아니라 테이블에 대한 변경 사항을 캡처합니다.

  • 감사 테이블을 다른 디스크 세트에 배치하여 기본 테이블의 I / O로드를 줄일 수 있습니다.

  • 현재 버전을 포함하여 전체 히스토리를 표시하는 테이블과 감사 로그 테이블의 통합을 기반으로하는보기를 사용할 수 있습니다.

  • 감사 사용자가 응답 적으로 쿼리 할 수 ​​있도록 필요에 따라 감사 로그 테이블을 색인화 할 수 있습니다. 평소와 같이 인덱스 선택은 쿼리 성능과 업데이트 오버 헤드 간의 균형을 유지합니다.


변경 사항에 대한 로그를 유지 해야하는 1000 테이블이 있으면 1000 그림자 테이블을 만들어야한다고 말하려고합니까? 변경 사항을 캡처하기위한 1000 개의 트리거? 그렇다면 가짜 아이디어입니다 ... 우리는 변경된 데이터를 캡처하고 기록하기 위해 단일 기록 테이블과 단일 트리거를 만들 수 있습니다. 우리는 테이블에 오래된 행 데이터와 새 행 데이터를 XML로 저장할 수 있습니다. 많은 사람들이하는 일입니다.
Thomas

1
1000 개의 테이블에 대해 시스템 데이터 사전에서 정의를 읽고 트리거 및 테이블 정의를 생성하는 utlity를 작성합니다. 560 테이블이있는 시스템에서 수행했으며 정상적으로 작동합니다.
ConcernedOfTunbridgeWells

0

단일 테이블을 사용하여 모든 버전의 데이터를 저장하는 많은 CMS 시스템 (Wordpress 포함)을 알고 있습니다. 그러나 블로그 게시물이있는 테이블에 대해서만이 작업을 수행하면됩니다. Wordpress 데이터베이스 구조를 참조하십시오 .

또한 각 행이 통과하는 레코드 수와 개정 수는 결정에 중요한 역할을합니다.


0

CMS 버전 관리 정보 drupal의 경우 이전 값을 저장하는 엔티티의 모든 필드에 대해 특수 테이블을 만듭니다. 이러한 개념을 사용하면 데이터를 잘 조작 할 수 있지만 비싸다고 생각합니다. 내 솔루션은 내 객체를 XML 형식으로 변환하고 다른 필드 (changetime, id ...)와 함께 문자열로 저장하는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.