사용자가 편집 할 수있는 콘텐츠가 포함 된 웹 프로젝트를 진행 중이며 데이터베이스에있는 실제 콘텐츠의 버전 추적을 수행하고 싶습니다. 기본적으로 위키 스타일 변경 기록을 구현하고 싶습니다.
몇 가지 배경 조사를 통해 데이터베이스 스키마의 버전을 관리하는 방법에 대한 많은 문서를 볼 수 있지만 (실제로 이미 제어되고 있음) 데이터베이스 버전 변경 사항 을 추적하는 방법에 대한 기존의 전략은 적어도 스키마 버전 관리 작업에서 눈에 띄지 않습니다. 내 검색에서.
내 변경 추적을 구현하는 몇 가지 방법을 생각할 수 있지만 모두 다소 거친 것처럼 보입니다.
- 각 변경 사항에 전체 행을 저장하고 기본 키를 사용하여 행을 소스 ID와 다시 관련시킵니다 (현재 내가 기대하는 것, 가장 간단합니다). 그러나 많은 작은 변화는 많은 테이블 팽창을 일으킬 수 있습니다.
- 변경 사항을 관련 열과 다시 관련시키기 위해 열 이름과 함께 각 변경 전 / 후 / 사용자 / 타임 스탬프를 저장하십시오.
- 각 열에 대한 테이블로 이전 / 이후 / 사용자 / 타임 스탬프를 저장하십시오 (너무 많은 테이블이 생성 될 수 있음).
- 각 변경 사항에 대해 diffs / user / timestamp를 열로 저장하십시오 (이는 특정 날짜로 돌아가려면 전체 개입 변경 히스토리를 걸어야 함을 의미합니다).
가장 좋은 방법은 무엇입니까? 내 자신을 굴리는 것은 아마도 다른 사람 (더 나은) 코드베이스를 재발 명하는 것처럼 보입니다.
PostgreSQL의 보너스 포인트.
답변
내가 일반적으로 사용한 기술은 end_timestamp 필드와 함께 전체 레코드를 저장하는 것입니다. 단 하나의 행에만 end_timestamp가 null 인 비즈니스 규칙이 있으며 이는 현재 활성 컨텐츠입니다.
이 시스템을 채택하는 경우 규칙을 적용하기 위해 색인 또는 제약 조건을 추가하는 것이 좋습니다. 고유 인덱스는 하나의 null 만 포함 할 수 있으므로 Oracle에서는 쉽습니다. 다른 데이터베이스가 더 문제가 될 수 있습니다. 데이터베이스에 규칙을 적용하면 코드를 정직하게 유지할 수 있습니다.
많은 작은 변경 사항이 부풀어 오를 것이라는 점은 정확하지만 코드 및보고 단순 성과는 균형을 이루어야합니다.
답변
Microsoft SQL Server를 사용하는 경우 Change Data Capture 라는 기능이 이미 있습니다. 여전히 이전 개정 에 액세스 하기 위해 코드를 작성해야 하지만 (CDC는 이에 대한 특정 뷰를 작성 함) 최소한 테이블의 스키마를 변경하거나 변경 추적 자체를 구현할 필요는 없습니다.
후드 아래에서 일어나는 일은 다음과 같습니다.
-
CDC는 개정을 포함하는 추가 테이블을 작성합니다.
-
원래 테이블이 예전처럼 사용되었습니다. 즉, 업데이트가이 테이블에 직접 반영됩니다.
-
CDC 테이블은 변경된 값만 저장하므로 데이터 복제가 최소로 유지됩니다.
변경 사항이 다른 테이블에 저장된다는 사실은 두 가지 중요한 결과를 초래합니다.
-
원본 테이블에서 선택하면 CDC가없는 것만 큼 빠릅니다. 잘 기억하면 CDC 는 업데이트 후에 발생 하므로 업데이트 속도도 동일합니다 (CDC가 데이터 일관성을 관리하는 방식은 잘 기억하지 못하지만).
-
원래 테이블의 스키마가 일부 변경되면 CDC가 제거됩니다. 예를 들어, 열을 추가하면 CDC는이를 처리하는 방법을 모릅니다. 반면에 인덱스 또는 제약 조건을 추가하는 것이 좋습니다. 자주 변경되는 테이블에서 CDC를 사용하면이 문제가 빠르게 발생합니다. CDC를 잃지 않고 스키마를 변경할 수있는 솔루션이있을 수 있지만 검색하지는 않았습니다.
답변
“철학적으로”문제를 코드에서 먼저 해결하십시오. 그런 다음 코드 및 데이터베이스와 “협상”하여이를 수행하십시오.
예를 들어 일반적인 기사를 다루는 경우 기사의 초기 개념은 다음과 같습니다.
class Article {
public Int32 Id;
public String Body;
}
그리고 다음으로 가장 기본적인 수준에서 개정 목록을 유지하고 싶습니다.
class Article {
public Int32 Id;
public String Body;
public List<String> Revisions;
}
그리고 현재의 몸은 단지 최신 개정판이라고 생각합니다. 그리고 그것은 두 가지를 의미합니다 : 나는 각 개정이 날짜 또는 번호를 매길 필요가 있습니다 :
class Revision {
public Int32 Id;
public Article ParentArticle;
public DateTime Created;
public String Body;
}
그리고 … 그리고 기사의 현재 본문은 최신 개정판과 구별 될 필요가 없습니다.
class Article {
public Int32 Id;
public String Body {
get {
return (Revisions.OrderByDesc(r => r.Created))[0];
}
set {
Revisions.Add(new Revision(value));
}
}
public List<Revision> Revisions;
}
몇 가지 세부 사항이 누락되었습니다. 그러나 그것은 아마도 두 개의 엔티티를 원한다는 것을 보여줍니다 . 하나는 기사 (또는 다른 헤더 유형)를 나타내고, 다른 하나는 개정 목록입니다 (그룹에 적합한 “철학적”의미가있는 필드를 그룹화). 코드는 개정 자체를 신경 쓰지 않기 때문에 처음에는 특별한 데이터베이스 제약 조건이 필요하지 않습니다. 이는 개정에 대해 알고있는 기사의 속성입니다.
따라서 “현재”기사를 표시하기 위해 특별한 방식으로 수정본을 플래그 지정하거나 데이터베이스 제약 조건에 의존 할 필요가 없습니다. 당신은 그것들을 타임 스탬프하고 (자동 -incedd ID도 괜찮을 것입니다), 그것들을 그들의 부모 기사와 관련시키고, “최신”이 가장 관련성이 높은 것을 아는 책임을 지도록 기사를 맡기십시오.
또한 ORM이 덜 철학적 인 세부 사항을 처리하도록하거나 또는 기본 제공 ORM을 사용하지 않는 경우 사용자 정의 유틸리티 클래스에서 숨길 수 있습니다.
훨씬 나중에 스트레스 테스트를 마친 후에는 해당 수정 속성을 지연로드로 만들거나 Body 속성을 지연 수정으로 최상위 수정 만하는 것에 대해 생각할 수 있습니다. 그러나이 경우 데이터 구조는 이러한 최적화를 수용하기 위해 변경하지 않아도됩니다.
답변
감사 추적 트리거 를 위한 PostgreSQL wiki 페이지가 있으며 필요한 작업을 수행 할 감사 로그를 설정하는 방법을 안내합니다.
변경의 전체 원본 데이터와 업데이트에 대한 새 값 목록 (삽입 및 삭제의 경우 하나의 값만 있음) 목록을 추적합니다. 이전 버전을 복원하려는 경우 감사 레코드에서 원본 데이터의 사본을 가져올 수 있습니다. 데이터에 외래 키가 포함 된 경우 일관성을 유지하기 위해 해당 레코드를 롤백해야 할 수도 있습니다.
일반적으로 데이터베이스 응용 프로그램이 현재 데이터에 대부분의 시간을 소비하는 경우 현재 데이터와 별도의 테이블에서 대체 버전을 추적하는 것이 좋습니다. 이렇게하면 활성 테이블 인덱스를보다 관리하기 쉽게 유지할 수 있습니다.
추적하는 행이 매우 크고 공간이 심각한 문제인 경우 변경 사항을 분석하고 최소한의 차이 / 패치를 저장하려고 시도 할 수 있지만 모든 종류의 데이터 유형을 처리하는 것이 더 많은 작업입니다. 이전에이 작업을 수행했으며 한 번에 하나씩 모든 변경 사항을 거꾸로 수행하여 이전 버전의 데이터를 다시 작성하는 것이 어려웠습니다.
답변
글쎄, 나는 가장 간단한 옵션, 구 버전의 행을 테이블 당 기록 로그에 복사하는 트리거로 마무리했다.
데이터베이스 팽창이 너무 많으면 필요한 경우 사소한 히스토리 변경 사항 중 일부가 축소되는 것을 볼 수 있습니다.
트리거 기능을 자동으로 생성하기를 원했기 때문에 솔루션이 다소 지저분 해졌습니다. SQLAlchemy이므로 상속 하이 진크를 수행하여 기록 테이블을 생성 할 수 있었지만 실제 트리거 함수는 PostgreSQL 함수를 올바르게 생성하고 하나의 테이블에서 또 다른 올바르게.
어쨌든, 그것은 모두 github에 있습니다 .