기록 / 시간 테이블에 대한 모범 사례?


11

기록을 추적하려는 특정 필드와 기록을 추적하지 않으려는 특정 필드가있는 객체가 있다고 가정합니다. 정규화 관점에서 볼 때 다음 스키마는 괜찮습니다.

CREATE TABLE MyObject AS (
    MyObjectId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectField1 VARCHAR(100) NOT NULL,
    MyObjectField2 VARCHAR(100) NOT NULL,
    MyObjectField3 VARCHAR(100) NOT NULL,
    MyObjectTrackedField1 VARCHAR(100) NOT NULL,
    MyObjectTrackedField2 VARCHAR(100) NOT NULL,
    MyObjectTrackedField3 VARCHAR(100) NOT NULL,
)
CREATE TABLE MyObjectHistory AS (
    MyObjectHistoryId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectId INT NOT NULL FOREIGN KEY REFERENCES MyObject(MyObjectId),
    MyObjectTrackedField1 VARCHAR(100) NOT NULL,
    MyObjectTrackedField2 VARCHAR(100) NOT NULL,
    MyObjectTrackedField3 VARCHAR(100) NOT NULL,
)

여기서 MyObjectHistory에는 최신 개정을 제외한 모든 대상에 대한 추적 필드가 포함됩니다. 또는 모든 추적 필드가 하나의 테이블에 있고 최신을 포함하여 모든 개정판이 다음과 같이 해당 테이블에 있어야합니다.

CREATE TABLE MyObject AS (
    MyObjectId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectField1 VARCHAR(100) NOT NULL,
    MyObjectField2 VARCHAR(100) NOT NULL,
    MyObjectField3 VARCHAR(100) NOT NULL,
)
CREATE TABLE MyObjectHistory AS (
    MyObjectHistoryId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectId INT NOT NULL FOREIGN KEY REFERENCES MyObject(MyObjectId),
    MyObjectTrackedField1 VARCHAR(100) NOT NULL,
    MyObjectTrackedField2 VARCHAR(100) NOT NULL,
    MyObjectTrackedField3 VARCHAR(100) NOT NULL,
)

@Joel

답변:


7

실질적인 데이터 액세스를 위해 첫 번째 옵션의 구조를 사용해야하지만 대신 내역 테이블에 현재 버전포함하여 모든 버전의 추적 열 값 유지해야 합니다.

그 이유는 일반적으로 히스토리를보고자 할 때 현재 버전과 모든 과거 버전을 포함하려고하기 때문입니다. 역사를보고 싶지 않을 때는 길을 벗어나고 싶을 것입니다. 많은 경우에 이것은 히스토리를 별도의 스키마 또는 데이터베이스로 분리하는 것을 의미합니다. 히스토리를 현재 데이터와 동일한 스키마에 유지하더라도 히스토리 데이터 (현재 값 포함)를 보는 쿼리는 본질적으로 두 소스를 통합해야하기 때문에 훨씬 더 복잡합니다.


2

역사를 볼 필요가 거의 없지만 현재 값을 자주 볼 필요가 있기 때문에 첫 번째 버전을 선호합니다. 히스토리 테이블은 트리거에서 채워 져야하므로 데이터가 일반적으로 동기화되지 않는 것에 대해 걱정할 필요가 없습니다. 따라서 MyObject에 백만 개의 레코드가 있고 MyObjectHistory에 10,000,000 개의 레코드가 있다고 가정하십시오. 현재 값을 얻기 위해 많은 레코드가있는 테이블에 조인 하시겠습니까?

이제 현재 값보다 자주 또는 더 빈번하게 기록을 쿼리 해야하는 경우 두 번째 구조가 작동합니다. (그리고 특정 날짜를 기준으로 값을 표시하려는 경우 쿼리를보다 간단하게하기 위해 begindate 및 enddate 필드가 있습니다.)

BTW 변경 사항이 발생한 순서를 알 수 있도록 날짜 필드를 기록 테이블에 추가합니다. 일시적인 질서에는 신원에 의존 할 수 없습니다. 사전 가치에 관한 질문이 있거나 변경되었을 때, 당신은 알아야합니다. 또한 변경이 발생한 응용 프로그램 (여러 응용 프로그램이있는 경우) 및 / 또는 변경 한 사람의 값을 입력 할 수도 있습니다.


0

# 1에는 몇 가지 중요한 이유가 있습니다. 첫 번째는 HLGEM이 지적한 크기 문제이지만 다른 중요한 문제도 있습니다.

일반적으로 감사 추적에는 시간이 지남에 따라 요구 사항이 개발됩니다. 데이터베이스 사용자, 변경 시간 등을 추적하려고 할 수도 있습니다. 감사 추적 요구 사항 및 기본 테이블은 시간이 지남에 따라 다소 독립적으로 변경 될 수 있습니다. 마지막으로 일정 기간이 지나면 완전히 독립적 인 테이블과 감사 추적 데이터를 제거하려고 할 수 있습니다.

물론 과거 데이터가 현재 계산에 사용될 수 있고 레코드 수는 상대적으로 적을 수 있기 때문에 LedgerSMB의 세율과 같이 완전히 병합하려는 경우가 있습니다.

그러나 이와 같은 테이블에 객체를 저장하면 정상적으로 표준화 된 디자인으로 이어지지 않는 것이 좋습니다. 내 경험상, 정규화 된 좋은 저장소와 응용 프로그램 개체 모델간에 캡슐화를 원합니다.


2
“정상화 된 스토리지와 응용 프로그램 객체 모델 간의 캡슐화”란 무엇을 의미합니까? 이 아이디어를 설명하거나 예를 들어 주시겠습니까?
cubetwo1729
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.