데이터베이스 테이블에 "레코드 상태"열을 갖는 것이 좋지 않습니까?


12

먼저 상태 열이 테이블의 레코드 (행)로 표시되는 실제 항목 의 상태를 반영 하지 않는다는 것을 명확히 해야합니다. 오히려 레코드 자체의 상태를 표시하기위한 것입니다.

승인 / 삭제 / 잠금 / 보류 / 거부 등과 같이 활성 / 비활성 또는 복잡성만큼 간단 할 수 있습니다. 상태는 부울 / 짧은 정수 열 또는 단일 문자 열에 저장 될 수 있으며, true/ 1= 활성 또는 A= 승인되었습니다.

기본 아이디어는 응용 프로그램에서 휴지통 / 휴지통과 같은 복구를 지원하고 데이터베이스에서이를 시뮬레이션하는 것입니다. 사용자가 레코드를 "삭제"할 수있는 프런트 엔드 GUI 또는 기타 인터페이스가있는 경우 실제로 테이블에서 레코드를 삭제하는 것이 아니라 단순히 레코드 상태를 비활성 또는 삭제됨으로 변경합니다. 인터페이스가 레코드를 가져올 때 항상 상태가 활성 또는 승인 된 조건과 일치하는 레코드 만 가져옵니다.

사용자가 실수하여 "삭제 된"레코드 (사용자 관점에서)를 복구해야하는 경우 DBA는 레코드를 활성 또는 승인 상태로 쉽게 패치 할 수 있습니다. 이는 백업을 검색하고 원본 레코드를 찾는 것보다 낫습니다. 그곳에. 또는 인터페이스 자체는 사용자가 삭제 된 레코드를 별도의보기로보고 필요에 따라 복원하거나 영구적으로 삭제할 수도 있습니다 (실제 레코드 삭제).

내 질문 :

  • 이것은 좋은 습관입니까, 아니면 나쁜 습관입니까?
  • 데이터 정규화에 영향을 줍니까?
  • 잠재적 인 함정은 무엇입니까?
  • 동일한 목표를 달성하는 다른 방법이 있습니까? (참고 참조)
  • 데이터베이스가 특정 상태에 대해서만 데이터에 대해 고유 한 제약 조건을 적용하도록하려면 어떻게해야합니까 (그러나 다른 상태에 대해서는 중복을 허용하지 않습니까)?
  • 데이터베이스가 기본적으로 "휴지통"과 같은 기능이나 테이블 추적 / 복구 기능을 제공하지 않아서 인터페이스가 실제 레코드를 걱정없이 삭제할 수있게하는 이유는 무엇입니까?

참고 : 별도의 기록 테이블을 유지 관리하는 방법에 대해 읽었지만 스토리지 측면에서 더 나빠 보이고 트리거를 생성하고 추적 된 테이블의 스키마로 트리거를 최신 상태로 유지해야합니다.


고유 제한 조건 (이미 이름 지정)의 문제점은 히스토리 테이블이 종종 선호되는 이유입니다. 원래 테이블에 고유 키 제한 조건을 유지하고이를 히스토리 테이블에 추가 할 수 없습니다. 그들을 위해 사용하는 특정에 (DB에 따라 다름) 스토리지 옵션은, 그래서 그들은 종종 더 나은 , 스토리지 측면에서 나쁘지. 이러한 테이블이 많으면 트리거 및 히스토리 테이블을 직접 작성하지 말고 생성해야합니다. 그러면 테이블을 "최신"으로 유지하는 방법에 대한 문제점이 해결됩니다.
Doc Brown

답변:


5

나는 이것을 "소프트 삭제"로 알고있다. 실제로는 아니지만 레코드를 "삭제됨"으로 표시합니다.

이것은 좋은 습관입니까, 아니면 나쁜 습관입니까?

때에 따라 다르지.
이것이 사용자에게 [많이] 필요한 것이라면 아마 좋은 것입니다. 그러나 대다수의 경우, 나는 그것이 약간의 이익을 위해 많은 오버 헤드를 추가하고 있다고 주장합니다.

데이터 정규화에 영향을 줍니까?

아니,하지만 것입니다 데이터의 색인 생성에 영향을 미칩니다.
쿼리에서 이러한 행이 가능한 빨리 제외되도록 인덱스에 "삭제 된"열을 포함시켜야합니다.

잠재적 인 함정은 무엇입니까?

데이터가 조금 더 복잡해집니다. 데이터 근처의 모든 곳에서 발생하는 모든 추가 "실제로 존재하지 않는"레코드에 대해 "알아야"합니다. 또는 해당 행을 제외하고 해당보고를 선택 도구 (예 :보고 도구)에서 사용하는 테이블에 대해보기를 작성해야합니다.

데이터베이스 크기가 커질 수 있습니다. 이 행을 실제로 삭제하지 않으면 여전히 행이 남아 공간을 차지합니다. 특히 인덱스에 인덱스를 포함 시켰기 때문에 문제가 될 수도 있고 아닐 수도 있습니다. 따라서 사용하는 공간이 배가됩니다.

동일한 목표를 달성하는 다른 방법이 있습니까? (참고 참조)

아니, 아니

데이터베이스가 특정 상태에 대해서만 데이터에 대해 고유 한 제약 조건을 적용하도록하려면 어떻게해야합니까 (그러나 다른 상태에 대해서는 중복을 허용하지 않습니까)?

쉽지 않습니다. 선언적 참조 무결성 (외부 키 절)은이를 구현하는 가장 깔끔한 방법이며보고 도구와 같은 것들이 이러한 규칙을 선택하여 테이블 간의 관계를 쉽게 결정할 수 있습니다. 이러한 규칙은 "상태"에 관계없이 모든 레코드에 적용됩니다 (그리고 그 방법은 없습니다).

대안은 테이블 사이의 참조 무결성을 강화하고 필요한 모든 영리하고 조건부 작업을 수행하는 절차 코드 스 니펫 인 트리거를 사용하는 것입니다. 그것은 당신의 특별한 경우에는 좋지만, 선언적 RI의 이점의 대부분은 창 밖으로 나옵니다. 당신의 테이블 사이에는 [외부 적으로] 감지 할 수있는 관계가 없습니다. 그것은 방아쇠에 모두 숨겨져 있습니다.

데이터베이스가 기본적으로 "휴지통"과 같은 기능이나 테이블 추적 / 복구 기능을 제공하지 않아서 인터페이스가 실제 레코드를 걱정없이 삭제할 수있게하는 이유는 무엇입니까?

그들은?

이들은 결국 파일 시스템이나 스프레드 시트가 아닌 데이터베이스입니다.

그들이하는 일, 그들은 아주 잘 할 수 있습니다.

그들이하지 않는 것은 아마도 많은 수요가 없었을 것입니다.


좋은 대답이지만 대체 옵션이 있습니다 (예 : 행을 백업 테이블로 이동하여 복구 할 수있는 위치). 백업 테이블에는 최소한의 인덱스가있을 수 있습니다. 이렇게하면 기존 접근 방식 (큰 인덱스, 테이블 사용자의 혼동 가능성 등)에서 발생하는 문제가 최소화되지만 유지해야 할 다른 테이블이 있다는 사실이 분명히 추가됩니다 (항목이 외래 키 참조로 wrt되었음을 의미 함). 다른 몇 가지 옵션이 있지만 실제로 염두에 두는 옵션은 모든 사용자 지정 구현이며, 이러한 경우 모든 SQL 데이터베이스에서 일반적으로 제공되는 것은 아닙니다.
프랭크 홉킨스

9

연습입니다. 그것이 좋은지 나쁜지는 당신의 어플리케이션과 얼마나 자주 "삭제 취소"를 필요로하고 싶어하는지에 달려 있습니다. 시스템의 모든 테이블에 대해 이러한 종류의 열을 배치하려는 계획이 상당히 모호합니다. 시스템의 모든 테이블에서 삭제 취소를 실제로 귀찮게하지는 않을 것 같습니다. 그리고 구현이 필요합니다. 대부분의 경우 단일 테이블에서 단일 행을 삭제하지 않고 행을 삭제하고 관련 테이블을 업데이트하는 자식 테이블을 안내해야합니다.

나머지 질문의 대부분은 구현에 따라 다릅니다. 예를 들어, 오라클은 테이블의 모든 변경 사항을 추적하는 다양한 방법을 제공합니다 .FDA (Total Recall)는 모든 버전의 행에 대한 전체 기록을 유지하고 구현을 위해 데이터베이스 내 아카이빙을 수행하는 가장 최근의 접근 방식입니다. 소프트 삭제 패턴 다른 데이터베이스는 패턴을 구현하는 다른 방법을 제공 할 수 있습니다. 데이터베이스와 일시 삭제 삭제를 구현하는 방법에 따라 성능, 제약 조건 적용 여부 및 방법 등에 다양한 영향을 미칩니다. Oracle과 이야기하는 경우 함수 기반 인덱스를 사용하여 많은 작업을 수행 할 수 있습니다. SQL Server에서는 유사한 목적으로 필터링 된 인덱스를 사용할 수 있습니다.


Oracle Flashback은 내가 원하는 것을위한 이상적인 솔루션입니다. 오라클이 독점적입니다.
ADTC

4

MRP / ERP 시스템에서 "삭제를 위해 표식"필드를 사용하는 것이 매우 일반적입니다.

예를 들어, 더 이상 판매되지 않은 부품 또는 재고 레코드를 비활성 상태로 표시하려고하지만 여전히 미결 주문이 연결되어있을 수 있습니다. 레코드에서 실제 삭제를 수행하면 아직 선적되지 않은 주문, 아직 전기되지 않은 원장 항목, 월말까지 빌드되지 않은 히스토리 테이블 등에 영향을 줄 수 있습니다. 많은 시스템은 일련의 레코드를 통과하지 않으면 레코드 삭제를 허용하지 않습니다. 다른 테이블에 대한 유효성 검사 관계를 통해 계단식 삭제를 수행하는 경우 실제 삭제는 훨씬 더 파괴적 일 수 있습니다.

대신 삭제를 위해 플래그를 지정하여 레코드에 명확한 의도 표시를하고 나중에 모든 관련 테이블이 더 이상 참조하지 않는지 확인하면 예약 된 작업이 레코드를 삭제할 수 있습니다.

고객 테이블 및 기타 "장기"테이블에서이 기능에 대해서도 비슷한 경우가 있습니다. 플래그의 이름이 "배송 됨"또는 "취소됨"과 같이 될 수도 있지만, 주문과 같은 변동성이 큰 테이블에서도 의미가 있습니다. 동일한 기능을 수행합니다. 두 번째로 삭제하지 말고 퍼지 프로그램의 플래그로 사용하여 나중에 레코드 삭제를 확인합니다.


3

대안 솔루션으로, 이벤트 소싱을 사용하면 테이블 구조를 복잡하게 만들지 않고도 유사한 목표를 달성 할 수 있지만 이벤트 히스토리에 지속될 수있는 이벤트에 수정 사항을 작성해야하므로 데이터를 수정하기위한 코드를 좀 더 복잡하게 만듭니다. . 그러면 언제든지 데이터베이스를 다시 만들 수있어 매우 유용한 기능이 될 수 있습니다.

(이것은 당신이 "기록 테이블"이 의미하는 바라고 생각하지 않습니다. 변경 또는 삭제 된 레코드를 변경하기 전에 다른 테이블로 복사하기 만하면됩니다.)


흥미로운 개념. 이것이 어떻게 구현 될 수 있는지 살펴볼 것입니다.
ADTC

1

이 사용 사례에서이 패턴을 자주보고 사용합니다.

  • 오늘 유효한 값만 표시하려는 메타 데이터. 예를 들어 enabled = 1 인 드롭 다운 목록에서 자동차 제조업체 목록에서 선택하려면 ID, VALUE, ENABLED의 테이블 값은 1, 'Ford', 1 및 2, 'Edsel', 0, 3, 'Toyota'입니다. 1은 포드와 토요타의 선택만을 제공합니다
  • 패러다임이있는 사례 관리 시스템의 경우 사례는 한 번에 하나의 상태에만있을 수 있습니다. 이 경우 토글 열을 검사 제한 조건으로 0 또는 1의 값으로 CURRENT라고합니다. 사례가 한 상태에서 다른 상태로 이동하면 응용 프로그램은 이전 상태의 CURRENT 플래그를 0으로, 새로운 상태를 1로 업데이트합니다.

문제는 둘 이상의 응용 프로그램이나 웹 서비스가 테이블에 쓰는 경우 데이터 무결성을 강화하는 것입니다. 현재 상태가 하나만 있는지 어떻게 확인합니까? Justin Cave가 지적했듯이 기능을 기반으로 가상 인덱스를 작성하면 Oracle에서이를 수행 할 수 있지만 원래 단순한 개념으로 보이는 추가 오버 헤드가 발생합니다.


1

보고를 위해 데이터를 사용하려는 경우이 방법을 사용하는 것이 좋습니다 (충분히 큰 응용 프로그램에는 보고서가 있어야 함).

응용 프로그램 속도를 높이려면 실제로 데이터베이스에서보고 도구를 실행하지 않아야합니다. 따라서 다른 데이터베이스에 복사 / 동기화를 수행해야합니다.

recordStatus두 가지 상태 만 사용 ACTIVE하거나 타임 스탬프 CANCELLED와 함께 사용합니다 lastUpdatedOn. 나는 일반적으로 비즈니스 의미를 갖는 recordStatus것보다는 사용 status합니다.

보고 데이터베이스를 응용 프로그램과 동기화 할 때보 lastUpdatedOn고 쪽에서 대체 할 데이터베이스 를 알기 위해 필터를 설정 합니다.

보고 측면에는 일반적으로보고되지 않기 때문에 recordStatusor lastUpdatedOn필드 가 없습니다 . 따라서 CANCELLED상태를 볼 때 활성 레코드 만있는 방식으로보고 측에서 레코드를 삭제합니다.

거의 전체 동기화가 필요한 아카이브 나 백업과 같은 다른 유형의 저장소로 확장 할 수 있습니다. 그러나보고가 더 일반적인 목적입니다.

당신의 예를 참고 Approved, New, Pending그게 의미 사업을 현명하게 곳으로 만 가야를 의미 사업을이 같은 공통 필드로 넣어 좋은 생각되지 않습니다.

versionNo잠금은 레코드에 대한 낙관적 잠금을 제공하는 사용 하십시오.

대신 다른 옵션 recordStatusrecordActive저장 boolean공간을 적게 차지하고 인덱싱을 덜 하는 것으로 저장하는 것이지만 앞으로 예측할 수없는 향후 요구 사항에 대해 걱정할 것입니다.

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