태그 보관물: database-design

database-design

CRUD 이외의 접근법의 예가 있습니까? 논쟁을 벌입니다. 나는 CRUD의 U와

저는 프로그래머이지만 보관 인으로도 활동했습니다. 보관 인으로서 데이터를 유지하는 것이 중요합니다.

나는 종종 데이터 작업과 관련하여 동료들과 논쟁을 벌입니다. 나는 CRUD의 U와 D를 너무 좋아하지 않습니다. 오히려 레코드를 업데이트하고 새 레코드를 추가하고 이전 레코드에 대한 참조를 선호합니다. 이렇게하면 변경 기록을 작성할 수 있습니다. 또한 레코드 삭제를 좋아하지 않고 비활성으로 표시합니다.

이것에 대한 용어가 있습니까? 기본적으로 데이터를 작성하고 읽는 것입니까? 이 접근법의 예가 있습니까?



답변

레코드를 삭제 된 것으로 표시하는 것을 소프트 삭제라고 합니다. 업데이트에 대한 대체 문구를 들어 본 적이 없지만 이전 레코드를 임시로 삭제하고 새 레코드를 작성하는 원인이 될 수 있습니다.

이것은 논란의 여지가있는 기술입니다. 링크를 참조하십시오 : 프로 .


답변

변경 기록을 유지하는 데 따른 문제 중 하나는 데이터베이스를 복잡하게 만들고 사용 패턴에 따라 크기를 크게 늘릴 수 있다는 것입니다. 따라서 감사 추적을 별도의 위치에 저장하고 실제 응용 프로그램 테이블을 관련 데이터로만 채우는 것이 좋습니다. 따라서 응용 프로그램에서 CRUD 조작을 수행 할 때마다 변경 사항이 감사 테이블에 기록되고 CRUD 조작이 응용 프로그램 테이블에서 수행됩니다 (소프트 삭제 없음).

감사 내역을 별도로 유지하면 애플리케이션이 상호 작용할 수있는 원시적 인 데이터 저장소를 제공하면서도 필요한 경우 변경 기록을 유지합니다. 또한 비즈니스 요구 사항에 따라 감사 내역을 별도로 보관하거나 파기 할 수도 있습니다.


답변

EventSourcing 은 원하는 패턴처럼 들립니다.

간단한 “car”객체를 사용하여 예제를 보도록하겠습니다 (의사 C # 코드는 다음과 같습니다).

public class Car {
  public string Color { get; set; }
  public Car() { this.Color = "Blue"; }
}

CRUD 구현으로 자동차의 색상을 업데이트하면 이전 색상이 손실됩니다.

MyCar.Color = "Red";
MyCar.Save();  // Persist the update to the database and lose the previous data

이 정보 손실은 가장 피하고 싶은 것처럼 들립니다 (따라서 CRUD 패턴의 업데이트 및 삭제 부분에 대한 싫어요).

변경 사항을 업데이트 할 때 이벤트에 응답하기 위해 자동차 클래스를 다시 작성 해야하는 경우 다음과 같이 보일 수 있습니다.

public class Car {
    public string Color { get; private set; } // Cannot be set from outside the class

    public void ApplyEvent(CarColorChangedEvent e) {
      this.Color = e.Color;
    }
}

이제이 객체의 색상을 어떻게 업데이트할까요? CarColorChanged 이벤트를 만들 수 있습니다 !

var evnt = new CarColorChangedEvent("Red");
MyEventStore.save(evnt);
MyCar.ApplyEvent(evnt);

실제 모델 객체에 대한 저장 부족이 있습니까? 모델을 직접 유지하는 대신 모델을 현재 상태로 만드는 이벤트를 유지하기 때문입니다. 이러한 이벤트는 변경 불가능 해야합니다 .

이제 빨리 감고 몇 번 더 색상을 바꾸겠습니다.

var evnt = new CarColorChangedEvent("Green");
MyEventStore.save(evnt);
MyCar.ApplyEvent(evnt);

var evnt = new CarColorChangedEvent("Purple");
MyEventStore.save(evnt);
MyCar.ApplyEvent(evnt);

이벤트 저장소 (관계 데이터베이스, 파일 기반 등일 수 있음)를 살펴보면 자동차 객체와 관련된 일련의 이벤트가 표시됩니다.

CarColorChangedEvent => Red
CarColorChangedEvent => Green
CarColorChangedEvent => Purple

해당 자동차 객체를 재 구축하려면 새 자동차 객체를 생성하고 이벤트 저장소에서 해당 객체에 이벤트를 적용하면됩니다.

var MyCar = new Car();
var events = MyDatabase.SelectEventsForCar("CarIdentifierHere");
foreach(var e in events) {
  MyCar.ApplyEvent(e);
}
Console.WriteLine(MyCar.Color); // Purple

이벤트 스트림을 사용하면 새 자동차 오브젝트를 작성하여 자동차 상태를 이전 기간으로 롤백하고 원하는 이벤트 만 적용 할 수 있습니다.

var MyCar = new Car();
var event = MyDatabase.GetFirstEventForCar("CarIdentifierHere");
MyCar.ApplyEvent(e);
Console.WriteLine(MyCar.Color); // Red

답변

이벤트 소싱은 갈 길이며, Greg Young이 그것에 대해 무엇을 말해야하는지 살펴 봐야합니다.

http://goodenoughsoftware.net/

또한 그의 데이터베이스 (이벤트 저장소)에서이 프리젠 테이션을 살펴보십시오. 다른 비디오도 찾을 수 있습니다.

http://oredev.org/2012/sessions/a-deep-look-into-the-event-store

삭제 된 항목을 구체적으로 검색 할 수 있어야하는 경우를 제외하고는 “소프트 삭제”답변을 사용하지 않겠지 만 삭제 된 것이 아니라 보관 된 것으로 생각해서는 안됩니다. 여기서는 용어가 매우 중요하다고 생각합니다.

“버전 테이블”도 유지하고 싶지 않습니다. 내가 본 모든 “버전 테이블” (버그 등으로 인해 손상된 7 년 동안의 데이터 손상을 포함하여 현재 정리하려고하고 있습니다. . 그) 단지 손상으로하기 때문에 혹시 돌아가서 손상이 엉망하는 데이터를 다시 만들 수 없기 때문에 때문에 당신이 여전히 잃게 데이터 코드의 버그와 결국 손상 결국.

이벤트 소싱 모델에서는 그렇지 않습니다. 사용자가 한 일을 항상 정확하게 재생할 수 있습니다. 이것이 CRUD와 이벤트 소싱의 매우 중요한 차이점입니다. 이벤트 소싱 아키텍처는 이벤트를 데이터 객체 또는 도메인 모델 객체가 아닌 이벤트 저장소에 저장합니다. 이벤트는 여러 개체에 쉽게 영향을 줄 수 있습니다. 장바구니의 각 항목을 실제 주문으로 변환하는 장바구니 솔루션을 생각해보십시오. 하나의 이벤트는 모든 품목 오브젝트와 장바구니 오브젝트에 영향을 미치며이 오브젝트는 주문 오브젝트로 변환됩니다.

데이터베이스의 모든 테이블에 각 행의 버전이 지정된 복사본을 유지 한 경우 해당 버전 테이블을 유지하는 데 엄청난 공간과 성능 오버 헤드를 언급하지 않고 특정 타임 스탬프로 되 감는 공포를 상상해보십시오.

이벤트 소싱을 사용하면 특정 시점까지 이벤트를 재생하여 쉽게 되 감을 수 있습니다. 스냅 샷을 사용하여 빨리 감기를 수행 할 수 있지만 이는 모두 구현의 문제입니다.

그러나 데이터를 잃지 않는 데 특히 관심이있는 것으로 생각할 때 얻을 수있는 진정한 이점은이 데이터를 저장하는 코드에서 버그를 발견하면 다시 돌아가서 데이터를 정리할 필요가 없다는 것입니다 (데이터가 거의 완벽하지 않기 때문에 종종 불가능합니다). 대신 버그를 수정하고 모든 이벤트를 재생하십시오. 그런 다음 올바른 올바른 데이터가있는 데이터베이스를 갖게됩니다.

디버깅의 경우 사용자에게 수행 한 작업에 대한 정보를 요청하는 빈도는 얼마입니까? 수행 한 작업을 재생 한 다음 코드를 단계별로 실행하는 이유는 무엇입니까? 꽤 멋지다.

도움이 되었기를 바랍니다.


답변

정확하게 귀하의 예는 아니지만 구형 금융 시스템에서는 WORM 스토리지가 있습니다. “업데이트”해야 할 경우 새 레코드를 작성했으며 항상 마지막 레코드를 최신 레코드로 언급했지만 커밋 된 데이터를 덮어 쓸 수 없습니다.

많은 사람들이 그 아이디어를 나중의 시스템으로 가져 왔습니다. 나는 당신이 WORM 테이블이라고 부르는 것을 들었지만 그 서클에서만 들었습니다.


답변

예, 엔터프라이즈 시스템에서 일반적으로 두 가지 접근 방식이 있습니다.

  • “bi-temporal”모든 레코드에 유효하고 유효한 타임 스탬프가 있습니다 ( “현재”레코드의 유효 날짜가 “forever”-null, “9999-12-31″또는 이와 같은 높은 값). “유효한 날짜”날짜가 현재 시간으로 설정되는 대신 레코드가 삭제되지 않으며 업데이트의 경우 현재 시간부터 유효하고 영원히 유효한 새 레코드가 삽입됩니다.
  • “히스토리 테이블”-레코드가 변경 될 때마다 이전 레코드의 사본이 이벤트에 대한 시간 소인이있는 히스토리 / 로그 테이블에 덤프됩니다.

두 가지 접근 방식 모두 세분성에 큰 차이가 있습니다. 예를 들어 주문 항목의 위젯 수량이 변경된 경우 전체 주문 또는 한 항목에 대해서만 이력을 유지합니까?

일반적으로 “이중”은 많은 추가 작업이며 “감사인이 12 월 31 일 현재 주문 상태를 얻습니다”와 같은 사용 사례가 많은 경우에만 가치가 있습니다.


답변

pdr 제안에 따라 “소프트 삭제” 사용할 수 있습니다 . 업데이트에 관해서는, 당신이 종류의 내 대답처럼 여기, 기록의 역사를 유지할 수 : /dba/28195/save-history-editable-data-rdbms/28201#28201 영업 이익은 싶었던 특정 종류의 데이터의 모든 버전을 추적 할 수 있어야합니다.