개정을위한 데이터베이스 설계?


125

프로젝트에는 데이터베이스의 엔터티에 대한 모든 개정판 (변경 기록)을 저장해야합니다. 현재 우리는이를 위해 2 가지 설계 제안을 가지고 있습니다.

예 : "직원"엔터티

디자인 1 :

-- Holds Employee Entity
"Employees (EmployeeId, FirstName, LastName, DepartmentId, .., ..)"

-- Holds the Employee Revisions in Xml. The RevisionXML will contain
-- all data of that particular EmployeeId
"EmployeeHistories (EmployeeId, DateModified, RevisionXML)"

디자인 2 :

-- Holds Employee Entity
"Employees (EmployeeId, FirstName, LastName, DepartmentId, .., ..)"

-- In this approach we have basically duplicated all the fields on Employees 
-- in the EmployeeHistories and storing the revision data.
"EmployeeHistories (EmployeeId, RevisionId, DateModified, FirstName, 
      LastName, DepartmentId, .., ..)"

이 일을하는 다른 방법이 있습니까?

"디자인 1"의 문제점은 데이터에 액세스해야 할 때마다 XML을 구문 분석해야한다는 것입니다. 이로 인해 프로세스 속도가 느려지고 개정 데이터 필드에 조인을 추가 할 수없는 등 몇 가지 제한 사항이 추가됩니다.

그리고 "디자인 2"의 문제점은 모든 엔터티의 각 필드를 복제해야한다는 것입니다 (우리는 개정을 유지하려는 약 70-80 개의 엔터티가 있습니다).



1
참고 : 그냥이 경우 그것은 .SQL 서버 2008 도움이 될 수 이상 table..visit에 변화의 쇼의 역사 기술이 simple-talk.com/sql/learn-sql-server/...가 더 알을하고 난 DB의 확신 오라클도 이와 같은 것을 가질 것입니다.
Durai Amuthan.H

일부 열은 XML 또는 JSON 자체를 저장할 수 있습니다. 그렇지 않다면 앞으로 일어날 수 있습니다. 이러한 데이터를 서로 중첩 할 필요가 없는지 확인하십시오.
jakubiszon

답변:


38
  1. 마십시오 하지 대해 IsCurrent 판별 속성으로 하나 개의 테이블에 모두 넣어. 이로 인해 문제가 발생하고 대리 키와 다른 모든 종류의 문제가 필요합니다.
  2. 디자인 2에는 스키마 변경에 문제가 있습니다. Employees 테이블을 변경하면 EmployeeHistories 테이블과 함께 제공되는 모든 관련 sprocs를 변경해야합니다. 스키마 변경 노력을 두 배로 늘릴 수 있습니다.
  3. 디자인 1은 잘 작동하며 제대로 수행하면 성능 저하 측면에서 많은 비용이 들지 않습니다. xml 스키마 및 인덱스를 사용하여 가능한 성능 문제를 극복 할 수 있습니다. xml 파싱에 대한 귀하의 의견은 유효하지만 xquery를 사용하여 쉽게 뷰를 만들 수 있습니다. xquery를 사용하면 쿼리에 포함시키고 조인 할 수 있습니다. 이 같은...
CREATE VIEW EmployeeHistory
AS
, FirstName, , DepartmentId

SELECT EmployeeId, RevisionXML.value('(/employee/FirstName)[1]', 'varchar(50)') AS FirstName,

  RevisionXML.value('(/employee/LastName)[1]', 'varchar(100)') AS LastName,

  RevisionXML.value('(/employee/DepartmentId)[1]', 'integer') AS DepartmentId,

FROM EmployeeHistories 

25
IsCurrent 트리거를 사용하여 하나의 테이블에 모두 저장하지 말아야하는 이유는 무엇입니까? 이것이 문제가되는 몇 가지 예를 알려 주시겠습니까?
Nathan W

@Simon Munro 기본 키 또는 클러스터 키는 어떻습니까? 빠른 검색을 위해 Design 1 기록 테이블에 추가 할 수있는 키는 무엇입니까?
gotqn

나는 전체 테이블 스캔SELECT * FROM EmployeeHistory WHERE LastName = 'Doe' 에서 간단한 결과를 가정합니다 . 응용 프로그램을 확장하는 것이 가장 좋습니다.
Kaii

54

여기서 물어볼 핵심 질문은 '누가 / 이력을 사용할 것인가?'입니다.

대부분 사람이 읽을 수있는 기록을보고 할 예정이라면 과거에이 체계를 구현했습니다.

'AuditTrail'이라는 테이블 또는 다음 필드가있는 테이블을 만듭니다.

[ID] [int] IDENTITY(1,1) NOT NULL,
[UserID] [int] NULL,
[EventDate] [datetime] NOT NULL,
[TableName] [varchar](50) NOT NULL,
[RecordID] [varchar](20) NOT NULL,
[FieldName] [varchar](50) NULL,
[OldValue] [varchar](5000) NULL,
[NewValue] [varchar](5000) NULL

그런 다음 테이블에서 업데이트 / 삽입을 수행 할 때마다 설정해야하는 'LastUpdatedByUserID'열을 모든 테이블에 추가 할 수 있습니다.

그런 다음 모든 테이블에 트리거를 추가하여 발생하는 모든 삽입 / 업데이트를 포착하고 변경된 각 필드에 대해이 테이블에 항목을 작성할 수 있습니다. 테이블에는 각 업데이트 / 삽입에 대해 'LastUpdateByUserID'가 제공되므로 트리거에서이 값에 액세스하여 감사 테이블에 추가 할 때 사용할 수 있습니다.

RecordID 필드를 사용하여 업데이트중인 테이블의 키 필드 값을 저장합니다. 결합 키인 경우 필드 사이에 '~'를 사용하여 문자열 연결을 수행합니다.

나는이 시스템에 단점이있을 것이라고 확신합니다-크게 업데이트 된 데이터베이스의 경우 성능이 저하 될 수 있지만 웹 응용 프로그램의 경우 쓰기보다 더 많은 읽기가 이루어지며 꽤 잘 작동하는 것 같습니다. 심지어 테이블 정의를 기반으로 트리거를 자동으로 작성하는 작은 VB.NET 유틸리티도 작성했습니다.

그냥 생각이야!


5
감사 된 테이블에 NewValue가 저장되므로 NewValue를 저장할 필요가 없습니다.
Petrus Theron

17
엄밀히 말하면, 사실입니다. 그러나 일정 기간 동안 동일한 필드에 많은 변경 사항이있을 경우 새 값을 저장하면 'Brian의 모든 변경 사항 표시'와 같은 쿼리가 한 번의 업데이트에 대한 모든 정보가 유지되므로 훨씬 쉽게 하나의 기록. 그냥 생각이야!
Chris Roberts

1
생각 sysname테이블 및 열 이름에 대한보다 적절한 데이터 유형이 될 수 있습니다.
Sam

2
sysname을 사용하는 @Sam은 값을 추가하지 않습니다. 혼란 스러울 수도 있습니다 ... stackoverflow.com/questions/5720212/…
Jowen

19

데이터베이스 프로그래머 블로그 의 히스토리 테이블 기사 가 유용 할 수 있습니다. 여기에서 제기 된 일부 요점을 다루고 델타 스토리지에 대해 설명합니다.

편집하다

에서 역사 테이블 에세이, 저자 ( 케네스 다운스 ), 최소 7 개 컬럼의 역사 테이블을 유지하는 것이 좋습니다 :

  1. 변화의 타임 스탬프
  2. 변경 한 사용자
  3. 변경된 레코드 (이력이 현재 상태와 별도로 유지되는 위치)를 식별하는 토큰
  4. 변경 사항이 삽입, 업데이트 또는 삭제인지 여부
  5. 오래된 가치
  6. 새로운 가치
  7. 델타 (숫자 값 변경).

절대로 변경되지 않거나 기록이 필요하지 않은 열은 팽창을 피하기 위해 기록 테이블에서 추적해서는 안됩니다. 숫자 값에 델타를 저장하면 이전 값과 새 값에서 파생 될 수 있지만 후속 쿼리가 더 쉬워 질 수 있습니다.

히스토리 테이블은 비 시스템 사용자가 행을 삽입, 갱신 또는 삭제하지 못하도록 안전해야합니다. 전체 크기를 줄이고 (사용 사례에서 허용하는 경우) 주기적 제거 만 지원해야합니다.


14

우리는 Chris Roberts가 제안한 솔루션과 매우 유사한 솔루션을 구현했으며 이는 우리에게 잘 작동합니다.

유일한 차이점은 새로운 가치 만 저장한다는 것입니다. 이전 값은 결국 이전 기록 행에 저장됩니다.

[ID] [int] IDENTITY(1,1) NOT NULL,
[UserID] [int] NULL,
[EventDate] [datetime] NOT NULL,
[TableName] [varchar](50) NOT NULL,
[RecordID] [varchar](20) NOT NULL,
[FieldName] [varchar](50) NULL,
[NewValue] [varchar](5000) NULL

열이 20 개인 테이블이 있다고 가정하겠습니다. 이렇게하면 전체 행을 저장하지 않고 변경된 정확한 열만 저장하면됩니다.


14

디자인 1을 피하십시오. 예를 들어 관리자 콘솔을 사용하여 자동 또는 "수동으로"이전 버전의 레코드로 롤백해야하는 경우 매우 유용하지 않습니다.

디자인 2의 단점은 실제로 보이지 않습니다. 두 번째 기록 테이블에는 첫 번째 기록 테이블에있는 모든 열이 포함되어야한다고 생각합니다. 예를 들어 mysql에서는 다른 테이블 ( create table X like Y) 과 동일한 구조로 테이블을 쉽게 만들 수 있습니다 . 그리고 라이브 데이터베이스에서 레코드 테이블의 구조를 변경하려고 할 때는 alter table어쨌든 명령 을 사용해야 합니다. 또한 이력 테이블에 대해서도 이러한 명령을 실행하는 데 큰 노력을 기울이지 않아도됩니다.

노트

  • 레코드 테이블에는 최신 개정 만 포함됩니다.
  • 히스토리 테이블에는 레코드 테이블의 모든 이전 레코드 레코드가 포함됩니다.
  • 히스토리 테이블의 기본 키는 추가 된 레코드 테이블의 기본 키입니다. RevisionId 열 .
  • ModifiedBy특정 개정을 작성한 사용자 와 같은 추가 보조 필드에 대해 생각해보십시오 . DeletedBy특정 개정을 삭제 한 사람을 추적 하는 필드가 필요할 수도 있습니다 .
  • DateModified의미 가 무엇인지 생각하십시오 .이 특정 개정이 작성된 위치를 의미하거나이 특정 개정이 다른 개정으로 대체 된시기를 의미합니다. 전자는 필드가 레코드 테이블에 있어야하며 첫눈에 더 직관적 인 것 같습니다. 그러나 두 번째 솔루션은 삭제 된 레코드 (이 특정 개정이 삭제 된 날짜)에 더 실용적인 것으로 보입니다. 첫 번째 해결책을 찾으면 두 번째 필드 DateDeleted가 필요할 것입니다 (물론 필요한 경우에만). 당신과 당신이 실제로 기록하고 싶은 것에 달려 있습니다.

디자인 2의 작업은 매우 간단합니다.

수정
  • 레코드 테이블에서 기록 테이블로 레코드를 복사하고 새 RevisionId (레코드 테이블에없는 경우)를 제공하고 DateModified를 처리합니다 (해석 방법에 따라 다름)
  • 레코드 표에서 레코드를 정상적으로 업데이트합니다.
지우다
  • 수정 작업의 첫 번째 단계와 정확히 동일합니다. 선택한 해석에 따라 DateModified / DateDeleted를 적절하게 처리하십시오.
삭제 취소 (또는 롤백)
  • History 테이블에서 가장 높은 (또는 특정?) 개정을 가져와 Records 테이블에 복사
특정 레코드에 대한 개정 내역 표시
  • 히스토리 테이블 및 레코드 테이블에서 선택
  • 이 작업에서 정확히 무엇을 기대하는지 생각하십시오. 아마도 DateModified / DateDeleted 필드에서 필요한 정보를 결정할 것입니다 (위 참고 참조).

Design 2로 가면 유지 관리뿐만 아니라이를 수행하는 데 필요한 모든 SQL 명령이 매우 쉬워집니다! 아마, 훨씬 더 쉽게 될 것입니다 당신이 보조 열을 사용하는 경우 ( RevisionId, DateModified)도 기록 테이블에 - 정확히 동일한 구조에서 두 테이블을 유지 (고유 키 제외)! 이를 통해 간단한 SQL 명령이 가능하며 데이터 구조 변경에 견딜 수 있습니다.

insert into EmployeeHistory select * from Employe where ID = XX

거래를 사용하는 것을 잊지 마십시오!

스케일링 의 경우이 솔루션은 XML에서 데이터를 앞뒤로 변환하지 않고 인덱스를 사용하여 매우 간단한 쿼리 전체 테이블 행을 복사하기 때문에 매우 효율적입니다!


12

히스토리를 저장해야하는 경우, 추적중인 테이블과 동일한 스키마와 '개정 날짜'및 '개정 유형'열 (예 : '삭제', '업데이트')을 사용하여 새도우 테이블을 작성하십시오. 감사 테이블을 채우기 위해 일련의 트리거를 작성 (또는 생성-아래 참조)하십시오.

테이블에 대한 시스템 데이터 딕셔너리를 읽고 도구 테이블을 작성하는 섀도 테이블 및 트리거 세트를 작성하는 스크립트를 생성하는 도구를 작성하는 것은 매우 간단합니다.

이를 위해 XML을 사용하지 마십시오. XML 스토리지는이 유형의 트리거가 사용하는 기본 데이터베이스 테이블 스토리지보다 훨씬 덜 효율적입니다.


3
단순성을 위해 +1! 일부는 이후 변경에 대한 두려움으로 과도하게 엔지니어링하지만 대부분 실제로는 변경이 발생하지 않습니다! 또한 플래그 또는 상태가있는 하나의 테이블 (악몽)에 모두 기록하는 것보다 한 테이블의 기록과 다른 테이블의 실제 레코드를 관리하는 것이 훨씬 쉽습니다. 그것은 '키스'라고 불리며 일반적으로 장기적으로 보상합니다.
Jeach

+1 완전히 동의합니다. 정확히 내가 대답 한 내용을 말합니다 ! 간단하고 강력합니다!
TMS

8

Ramesh, 저는 첫 번째 접근 방식에 기반한 시스템 개발에 참여했습니다.
XML로 개정판을 저장하면 데이터베이스가 크게 증가하고 속도가 크게 느려집니다.
내 접근 방식은 엔티티 당 하나의 테이블을 갖는 것입니다.

Employee (Id, Name, ... , IsActive)  

여기서 IsActive 는 최신 버전의 표시입니다.

일부 추가 정보를 수정본과 연관 시키려면 해당 정보를 포함하는 별도의 테이블을 작성하고 PK \ FK 관계를 사용하여 엔티티 테이블과 연결하십시오.

이렇게하면 모든 버전의 직원을 하나의 테이블에 저장할 수 있습니다. 이 접근법의 장점 :

  • 간단한 데이터베이스 구조
  • 테이블이 추가 전용이되므로 충돌이 없습니다.
  • 단순히 IsActive 플래그를 변경하여 이전 버전으로 롤백 할 수 있습니다
  • 객체 이력을 얻기 위해 조인이 필요 없음

기본 키는 고유하지 않아야합니다.


6
IsActive 대신 또는 그 외에 "RevisionNumber"또는 "RevisionDate"열을 사용하므로 모든 개정을 순서대로 볼 수 있습니다.
Sklivvz

"parentRowId"를 사용하면 이전 버전에 쉽게 액세스 할 수있을뿐만 아니라 기본과 끝을 빠르게 찾을 수 있기 때문입니다.
chacham15 2016 년

6

내가 과거에 본 것을 본 방식은

Employees (EmployeeId, DateModified, < Employee Fields > , boolean isCurrent );

이 테이블에서 "업데이트"하지 않고 (isCurrent의 유효한 변경은 제외) 새 행을 삽입하십시오. 주어진 EmployeeId에 대해 1 개의 행만 isCurrent == 1을 가질 수 있습니다.

이를 유지 관리하는 복잡성은 뷰와 "대신"트리거 (Oracle에서는 다른 RDBMS와 비슷한 것으로 가정)에 의해 숨겨 질 수 있습니다. 테이블이 너무 커서 인덱스로 처리 할 수없는 경우 구체화 된 뷰로 이동할 수도 있습니다. .

이 방법은 괜찮지 만 복잡한 쿼리가 발생할 수 있습니다.

개인적으로, 나는 Design 2가 그것을하는 방법을 좋아합니다. 이것은 내가 과거에했던 일입니다. 이해하기 쉽고 구현하기 쉬우 며 유지 관리가 간단합니다.

또한 특히 읽기 쿼리를 수행 할 때 데이터베이스 및 응용 프로그램에 대한 오버 헤드가 거의 발생하지 않으므로 99 %의 시간이 소요될 수 있습니다.

또한 히스토리 테이블 및 트리거를 작성하여 유지 보수하기 위해 자동으로 작성하는 것이 매우 쉽습니다 (트리거를 통해 수행된다고 가정).


4

데이터 개정은 임시 데이터베이스 의 ' 유효 시간 '개념의 한 측면입니다 . 이에 대한 많은 연구가 이루어졌으며 많은 패턴과 지침이 등장했습니다. 나는 관심있는 사람들 을 위해이 질문에 대한 많은 언급으로 긴 답변을 썼습니다 .


4

나는 내 디자인을 당신과 공유 할 것이며 각 엔티티 유형 당 하나의 테이블이 필요하다는 점에서 두 디자인과 다릅니다. 데이터베이스 디자인을 설명하는 가장 좋은 방법은 ERD를 사용하는 것입니다.

여기에 이미지 설명을 입력하십시오

이 예제에는 employee 라는 엔터티가 있습니다 . user 테이블은 사용자의 레코드와 엔티티entity_revision을 보유합니다. 당신이 시스템에있을 것이라는 점을 모든 개체 유형에 대한 수정 기록을 보유 두 테이블입니다. 이 디자인의 작동 방식은 다음과 같습니다.

의 두 필드 ENTITY_IDREVISION_ID

시스템의 각 엔티티에는 고유 한 엔티티 ID가 있습니다. 귀하의 엔티티는 개정을 거칠 수 있지만 entity_id는 동일하게 유지됩니다. 이 엔터티 ID를 직원 테이블에 외래 키로 보관해야합니다. 또한 엔터티 유형을 엔터티 테이블 에 저장해야 합니다 (예 : '직원'). 이제 이름이 표시하는 바와 같이 edition_id는 엔티티 개정을 추적합니다. 내가 찾은 가장 좋은 방법은 employee_id 를 개정 _id로 사용하는 것 입니다. 이것은 다른 유형의 엔티티에 대해 중복 된 개정 ID를 가지지 만 이것은 나에게 아무런 영향을 미치지 않습니다 (귀하의 사건에 대해서는 잘 모르겠습니다). 확인해야 할 유일한 참고 사항은 entity_id와 개정 _id의 조합이 고유해야한다는 것입니다.

entity_revision 테이블 내에 는 상태를 나타내는 상태 필드 도 있습니다 . 그것은 세 가지 상태 중 하나를 가질 수 있습니다 , 또는latestobsoletedeleted (개정 날짜에 의존하지 않는 것은 당신에게 당신의 쿼리를 높일 수있는 좋은 거래를하는 데 도움).

개정 _id에 대한 마지막 참고 사항으로, 이후에 추가 할 각 엔티티 유형에 대해 entity_revision 테이블을 변경하지 않기 때문에 employee_id를 개정 _id에 연결하는 외래 키를 작성하지 않았습니다.

삽입

데이터베이스에 삽입하려는 각 직원에 대해 entityentity_revision에 레코드를 추가합니다 . 이 마지막 두 레코드는 레코드를 누가 언제 데이터베이스에 삽입했는지를 추적하는 데 도움이됩니다.

최신 정보

기존 직원 레코드에 대한 각 업데이트는 직원 테이블에 하나와 entity_revision에 하나씩 두 개의 삽입으로 구현됩니다. 두 번째는 기록이 누구와 언제 업데이트되었는지 알 수 있도록 도와줍니다.

삭제

직원을 삭제하기 위해 삭제를 나타내는 레코드가 entity_revision에 삽입되어 완료됩니다.

이 디자인에서 볼 수 있듯이 데이터베이스에서 데이터가 변경되거나 제거되지 않으며 각 항목 유형마다 하나의 테이블 만 필요합니다. 개인적으로 저는이 디자인이 정말 유연하고 다루기 쉽다는 것을 알게되었습니다. 그러나 귀하의 요구가 다를 수 있으므로 귀하에 대해 확신하지 못합니다.

[최신 정보]

새로운 MySQL 버전에서 파티션을 지원했기 때문에 내 디자인에도 최고의 성능 중 하나가 있다고 생각합니다. 필드를 사용하여 파티션을 나누고 필드를 entity사용하여 파티션을 나눌 수 있습니다 . 이렇게하면 디자인이 단순하고 깨끗하게 유지 되면서 쿼리가 훨씬 향상됩니다 .typeentity_revisionstateSELECT


3

실제로 감사 추적이 필요한 경우 감사 테이블 솔루션에 의존합니다 (예 : 다른 테이블에있는 중요 열의 비정규 화 된 사본이 완료 됨 UserName). 그러나 쓴 경험은 단일 감사 테이블이 큰 병목 현상을 초래할 것임을 나타냅니다. 모든 감사 테이블에 대해 개별 감사 테이블을 작성하는 것이 좋습니다.

실제 히스토리 (및 / 또는 향후) 버전을 추적해야하는 경우 표준 솔루션은 시작, 종료 및 기간 값의 조합을 사용하여 여러 행으로 동일한 엔티티를 추적하는 것입니다. 뷰를 사용하여 현재 값에 편리하게 액세스 할 수 있습니다. 이 방법을 사용하면 버전이 지정된 데이터가 변경 가능하지만 버전이 지정되지 않은 데이터를 참조하면 문제가 발생할 수 있습니다.


3

첫 번째 작업을 수행하려면 Employees 테이블에도 XML을 사용할 수 있습니다. 대부분의 최신 데이터베이스에서는 XML 필드를 쿼리 할 수 ​​있으므로 항상 문제가되지는 않습니다. 또한 최신 버전이든 이전 버전이든 관계없이 직원 데이터에 액세스하는 한 가지 방법이 더 간단 할 수 있습니다.

나는 두 번째 접근법을 시도 할 것입니다. DateModified 필드가있는 Employees 테이블이 하나만 있으면이를 단순화 할 수 있습니다. EmployeeId + DateModified는 기본 키이며 행을 추가하여 새 개정을 저장할 수 있습니다. 이렇게하면 이전 버전을 보관하고 보관에서 버전을 복원하는 것이 더 쉽습니다.

이를 수행하는 또 다른 방법 은 Dan Linstedt 의 데이터 저장소 모델 일 수 있습니다 . 나는이 모델을 사용하는 네덜란드 통계국 프로젝트를 수행했으며 꽤 잘 작동합니다. 그러나 일상적인 데이터베이스 사용에 직접 유용하다고 생각하지 않습니다. 그래도 그의 논문을 읽음으로써 아이디어를 얻을 수 있습니다.


2

어때요?

  • 직원 ID
  • 수정 한 날짜
    • 추적하려는 방법에 따라 개정 번호
  • ModifiedByUSerId
    • 추적하려는 다른 정보와 함께
  • 직원 분야

기본 키 (EmployeeId, DateModified)를 만들고 "현재"레코드를 얻으려면 각 직원 ID에 대해 MAX (DateModified)를 선택하면됩니다. IsCurrent를 저장하는 것은 매우 나쁜 생각입니다. 무엇보다도 계산이 가능하고 둘째로 데이터 동기화가 너무 쉽지 않기 때문입니다.

최신 레코드 만 표시하는 뷰를 만들 수 있으며 대부분 앱에서 작업하는 동안 해당 레코드를 사용합니다. 이 방법의 좋은 점은 중복 데이터가 없으며 모든 기록 또는 롤백 등을 얻기 위해 두 개의 다른 위치 (현재 직원의 현재 직원 및 직원 기록에 보관)에서 데이터를 수집 할 필요가 없다는 것입니다. .


이 방법의 단점은 두 개의 테이블을 사용하는 경우보다 테이블이 더 빨리 커진다는 것입니다.
cdmckay

2

기록 데이터를보고하려면 (보고 목적으로) 다음과 같은 구조를 사용해야합니다.

// Holds Employee Entity
"Employees (EmployeeId, FirstName, LastName, DepartmentId, .., ..)"

// Holds the Employee revisions in rows.
"EmployeeHistories (HistoryId, EmployeeId, DateModified, OldValue, NewValue, FieldName)"

또는 응용 분야를위한 글로벌 솔루션 :

// Holds Employee Entity
"Employees (EmployeeId, FirstName, LastName, DepartmentId, .., ..)"

// Holds all entities revisions in rows.
"EntityChanges (EntityName, EntityId, DateModified, OldValue, NewValue, FieldName)"

수정본을 XML로도 저장할 수 있으며 한 수정본에 대해 하나의 레코드 만 있습니다. 이것은 다음과 같습니다

// Holds Employee Entity
"Employees (EmployeeId, FirstName, LastName, DepartmentId, .., ..)"

// Holds all entities revisions in rows.
"EntityChanges (EntityName, EntityId, DateModified, XMLChanges)"

1
더 나은 : 이벤트 소싱 사용 :)
dariol

1

우리는 비슷한 요구 사항을 가지고 있었고, 우리가 발견 한 것은 종종 사용자 가 변경된 내용보고 싶어한다는 것입니다. 변경 사항을 롤백 할 필요는 없습니다.

유스 케이스가 무엇인지 잘 모르겠지만 외래 키 참조 및 열거의 친숙한 이름을 포함하여 비즈니스 엔티티의 변경 사항으로 자동 업데이트되는 테이블 작성 및 감사 테이블이 수행되었습니다.

사용자가 변경 사항을 저장할 때마다 이전 오브젝트를 다시로드하고, 비교를 실행하고, 변경 사항을 기록하고, 엔티티를 저장합니다 (모든 문제는 단일 데이터베이스 트랜잭션으로 수행됨).

이는 사용자에게 매우 효과적인 것으로 보이며 비즈니스 엔터티와 동일한 필드를 사용하여 완전히 별도의 감사 테이블을 만드는 데 따르는 어려움을 덜어줍니다.


0

ID 3, "bob", "123 main street", 다른 ID 3, "bob" "234 elm st"등과 같이 시간이 지남에 따라 특정 엔티티의 변경 사항을 추적하려는 것처럼 들릴 수 있습니다. "bob"에있는 모든 주소를 보여주는 개정 기록을 작성합니다.

이를 수행하는 가장 좋은 방법은 각 레코드에 "현재"필드를 있고 날짜 / 시간 테이블에 대한 타임 스탬프 또는 FK 일 것입니다.

그런 다음 인서트는 "현재"를 설정하고 이전 "현재"레코드에서 "현재"를 설정 해제해야합니다. 모든 히스토리를 원하지 않는 경우 쿼리는 "현재"를 지정해야합니다.

매우 큰 테이블이거나 많은 수의 개정이 예상되는 경우 여기에 추가 조정이 있지만 이것은 상당히 표준적인 접근 방식입니다.

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