문제

(데이터베이스 스키마 버전과 관련이 없음)

데이터베이스와 인터페이스하는 응용 프로그램에는 종종 많은 테이블의 데이터로 구성된 도메인 객체가 있습니다. 이 도메인 객체에 대해 응용 프로그램이 CV의 의미에서 버전 작성을 지원한다고 가정 해 봅시다.

일부 중재 도메인 개체의 경우이 요구 사항을 처리하기 위해 데이터베이스 스키마를 어떻게 설계 하시겠습니까? 공유 할 경험이 있습니까?

도움이 되었습니까?

해결책

개정 요구 사항에 대해 신중하게 생각하십시오. 코드 기반이 운영 체제에 내장 된 널리 퍼져있는 히스토리 추적이 있으면 매우 복잡해집니다. 보험 인수 시스템 스키마가 종종 1000 개 이상의 테이블을 실행하면 특히 나쁘다. 쿼리는 또한 매우 복잡한 경향이 있으며 이는 성능 문제로 이어질 수 있습니다.

역사적 상태가 실제로보고에만 필요한 경우, 이력을 추적하기 위해 뒷면에 매달려있는 데이터웨어 하우스 구조가있는 '현재 상태'트랜잭션 시스템을 구현하는 것을 고려하십시오. 천천히 변화하는 치수 임시 기록 추적 메커니즘을 운영 체제에 직접 포함시키는 것보다 역사적 상태를 추적하기위한 훨씬 간단한 구조입니다.

또한, 변경된 데이터 캡처 레코드의 변경 사항이 완료된 '현재 상태'시스템에 대해 간단합니다. 레코드의 기본 키는 변경되지 않으므로 동일한 엔티티의 다른 버전을 보유한 레코드와 일치 할 필요가 없습니다. 효과적인 CDC 메커니즘은 증분 창고 부하 프로세스를 상당히 가볍고 상당히 자주 실행할 수있게합니다. 역사적 상태 (거의, 거의, 옥시 모론)의 최신 추적이 필요하지 않은 경우 응용 프로그램에 직접 구축 된 전체 기록 추적 메커니즘보다 훨씬 간단한 코드베이스가있는 효과적인 솔루션이 될 수 있습니다.

다른 팁

과거에 내가 사용한 기술은 데이터베이스에 "세대"라는 개념을 갖는 것이 었습니다. 각 변경 사항은 데이터베이스의 현재 생성 번호를 증가시킵니다. 각 레코드에는 2 개의 세대 번호가 있습니다 (테이블에 2 개의 추가 열) - 레코드가 유효한 생성 및 생성은 유효한 생성이 유효합니다. 데이터가 현재 유효한 경우 두 번째 숫자는 NULL 또는 다른 일반 마커입니다.

데이터베이스에 삽입하려면 :

  1. 생성 번호를 증가시킵니다
  2. 데이터를 삽입하십시오
  3. 해당 데이터의 수명을 유효한 유효한 것으로 표시하고 유효한 NULL

일부 데이터를 업데이트하는 경우 :

  1. 현재 세대 번호에 유효한 것으로 수정하려는 모든 데이터를 표시합니다.
  2. 생성 번호를 증가시킵니다
  3. 현재 세대 번호에 새 데이터를 삽입하십시오

삭제는 현재 세대에서 종료되는 것으로 데이터를 표시하는 문제입니다.

특정 버전의 데이터를 얻으려면 어떤 생성을 찾아서 어떤 생성을 찾아서 해당 생성 버전간에 유효한 데이터를 찾으십시오.

예시:

사람을 만드십시오.

|Name|D.O.B  |Telephone|From|To  |
|Fred|1 april|555-29384|1   |NULL|

Tel No를 업데이트하십시오.

|Name|D.O.B  |Telephone|From|To  |
|Fred|1 april|555-29384|1   |1   |
|Fred|1 april|555-43534|2   |NULL|

프레드 삭제 :

|Name|D.O.B  |Telephone|From|To  |
|Fred|1 april|555-29384|1   |1   |
|Fred|1 april|555-43534|2   |2   |

엄격한 버전 작성의 대안은 데이터를 현재 및 히스토리의 두 표로 분할하는 것입니다.

현재 테이블에는 모든 라이브 데이터가 있으며, 모든 변경 사항이있는 모든 성능의 이점이 있습니다. 모든 변경 사항은 먼저 현재 데이터를 관련 "히스토리"테이블에 작성하여 변경 시점이 표시되는 날짜 마커와 함께합니다.

최대 절전 모드를 사용하는 경우 Jboss envers 옵션이 될 수 있습니다. 당신은 수업에 주석을 달기 만하면됩니다 @Audited 그들의 역사를 지키기 위해.

모든 버전간에 공통 정보가 포함 된 마스터 테이블에 마스터 레코드가 필요합니다.

그런 다음 각 어린이 테이블은 기본 키의 일부로 마스터 레코드 ID + 버전 번호를 사용합니다.

마스터 테이블 없이는 할 수 있지만 내 경험상 SQL 문을 훨씬 더 지저분하게 만드는 경향이 있습니다.

간단한 바보 같은 방법은 테이블에 버전 열을 추가하고 객체의 버전을 저장하고 해당 버전 번호를 기반으로 적절한 응용 프로그램 논리를 선택하는 것입니다. 이렇게하면 비용이 거의 들지 않습니다. 항상 좋습니다

ZODB + ZEO는 시점에서 모든 시점에 대한 완전한 롤백이있는 개정 기반 데이터베이스를 구현합니다. 가서 확인하십시오.

나쁜 부분 : Zope가 묶여 있습니다.

객체가 데이터베이스에 저장되면 객체를 수정 한 시간이 얼마나되지 않는지 알고 싶다면이 버전 작성 개념을 적용해야합니다.

버전화를 사용하면 최대 절전 모드 버전 번호를 0으로 삽입합니다. 데이터베이스에서 처음으로 객체가 저장 될 때. 나중에 해당 특정 객체에서 수정이 수행 될 때 버전을 자동으로 씩 씩 증가시킵니다. 이 버전 관리 개념을 사용하려면 응용 프로그램에서 다음 두 가지 변경 사항이 필요합니다.

Add one property of type int in our pojo class.

In hibernate mapping file, add an element called version soon after id element

우리가 같은 문제가 있는지 확실하지 않지만 현재 데이터 세트에 대한 많은 '제안 된'변경이 필요했습니다 (예 : 제안에 대한 제안, 즉 제안서).

소스 제어에서 분기를 생각하지만 데이터베이스 테이블 용.

우리는 또한 역사적 로그를 원했지만 이것은 가장 중요한 요소였습니다. 주요 문제는 비즈니스가 변경 승인에 대한 승인을 통해 6 개월 이상 걸릴 수있는 변경 제안을 관리하는 것이 었습니다.

아이디어는 사용자가 변경 사항을로드하고 실제로 변경 사항을 적용하지 않고 현재 데이터 상태를 작성, 편집, 삭제를 시작할 수 있다는 것입니다. 변경할 수있는 변경 사항을 되돌리거나 전체 변경 사항을 취소하십시오.

내가 이것을 달성 할 수 있었던 유일한 방법은 내 버전 테이블에 공통 필드 세트를 갖는 것입니다.

루트 ID: 필수 - 레코드의 첫 번째 버전이 생성 될 때 기본 키로 한 번 설정하십시오. 이것은 항상 기본 키를 나타내며 각 버전의 레코드에 복사됩니다. 관계 열을 명명 할 때 루트 ID를 고려해야합니다 (예 : Parent_id 대신 Parent_Root_id). 루트 ID는 초기 버전의 기본 키이기도하므로 실제 기본 키에 대해 외래 키를 만들 수 있습니다. 실제 원하는 행은 아래 정의 된 버전 필터에 의해 결정됩니다.

ID를 변경하십시오: 필수 - 모든 레코드가 변경, 업데이트, 변경을 통해 삭제됩니다.

ID에서 복사했습니다: nullable- null은 새로 생성 된 레코드를 표시하고, NULL NOT NULL은 어떤 레코드 ID가 업데이트되었을 때 클로닝되었는지를 나타냅니다.

날짜/시간부터 효과적입니다: NULLABLE- NULL은 제안 된 레코드를 표시하고, NOLL NOT은 레코드가 현재가되었는지를 나타냅니다. 불행히도 루트 ID에 대해 여러 널 값이있을 수 있으므로 고유 한 인덱스를 루트 ID/효과로 배치 할 수 없습니다. (레코드 당 단일 제안 된 변경으로 자신을 제한하지 않는 한)

날짜/시간까지 효과적입니다: nullable- 널 null은 현재/제안을 표시하며, NOL은 역사적이되었는지를 나타냅니다. 기술적으로 필요하지는 않지만 현재 데이터를 찾는 쿼리 속도를 높이는 데 도움이됩니다. 이 필드는 수작업에 의해 손상 될 수 있지만,이 경우 날짜/시간으로부터 유효한 곳에서 재건 될 수 있습니다.

플래그 삭제: Boolean- 전류가되면 레코드를 삭제하는 것이 제안되면 true로 설정됩니다. 삭제가 커밋되면 날짜/시간에 유효한 날짜/시간이 날짜/시간의 유효 값으로 설정되어 현재 데이터 세트에서 필터링됩니다.

변경에 따라 현재 데이터 상태를 얻는 쿼리는 다음과 같습니다.

SELECT * FROM table WHERE (CHANGE_ID IN :ChangeId OR (EFFECTIVE_FROM <= :Now AND (EFFECTIVE_TO IS NULL OR EFFECTIVE_TO > :Now) AND ROOT_ID NOT IN (SELECT ROOT_ID FROM table WHERE CHANGE_ID IN :ChangeId)))

(Change-on-Change 배수의 필터링은이 쿼리 외부에서 수행됩니다).

현재 데이터 상태를 한 시점에 가져 오는 쿼리는 다음과 같습니다.

SELECT * FROM table WHERE EFFECTIVE_FROM <= :Now AND (EFFECTIVE_TO IS NULL OR EFFECTIVE_TO > :Now)

(root_id, explud_from), (expective_from, exploy_to) 및 (change_id)에서 생성 된 공통 색인.

누군가가 더 나은 솔루션을 알고 있다면 나는 그것에 대해 듣고 싶습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top