데이터베이스에서 삭제를 어떻게 처리해야합니까?


44

사용자가 마음을 바꾸고 삭제 된 레코드를 복구 할 수 있도록 웹 응용 프로그램에서 "삭제 취소"기능을 구현하고 싶습니다. 이것을 구현하는 방법에 대한 생각? 내가 고려한 일부 옵션은 실제로 해당 레코드를 삭제하고 변경 사항을 별도의 감사 테이블에 저장하거나 레코드를 삭제하지 않고 부울 "삭제 된"열을 사용하여 삭제 된 것으로 표시하는 것입니다. 후자의 솔루션은 일반적인 상황에서 "삭제 된"레코드를 무시하기 위해 추가 응용 프로그램 논리가 필요하지만 응용 프로그램 측에서 레코드 복구를 훨씬 쉽게 구현할 수 있습니다.


두 번째 경우에는 적절한 경과 시간이 지난 후 플래그가 지정된 레코드를 삭제하거나 이동해야한다는 점을 언급하지 않았습니다.
Abie

어떤 데이터베이스를 사용하고 있습니까?
Evan Carroll

임시 테이블은 SQL Server 2016 이상에 가장 적합한 솔루션입니다.
Sameer

답변:


37

네, 분명히 두 번째 옵션을 선택하지만 날짜 필드에 필드를 하나 더 추가합니다.

따라서 다음을 추가하십시오.

delete       boolean
delete_date  timestamp

삭제 취소 작업을위한 시간을 제공 할 수 있습니다.

시간이 1 시간 미만이면 삭제를 취소 할 수 있습니다.

삭제 된 항목을 실제로 삭제하려면 delete가 true로 설정되고 1 시간보다 큰 시간으로 설정된 모든 항목을 정리하고 24 시간마다 실행되는 cron 탭으로 저장하는 저장 프로 시저를 작성하십시오.

시간은 단지 예일뿐입니다.


또는이 플래그 cleaned와 관련된 데이터가 올 바르고 포괄적으로 삭제되었음을 나타내는 다른 플래그 또는 무언가 가있을 수 있습니다 . cleanedtrue가 아니면 레코드를 삭제 취소 할 수 있으며이 경우 복구 할 수 없습니다.
Gaurav

14
이것이 일반적인 접근 방식입니다. 일반적으로 부울 deleted_at의 의미 deletedelete_date타임 스탬프 를 모두 포함하는 하나의 필드 를 사용 합니다 . 경우 deleted_atIS가 NULL처리하는 경우가 delete있습니다 FALSEdelete_date입니다 NULL, deleted_at경우에 타임 스탬프 핸들 포함 delete입니다 TRUE그리고 delete_date당신에게 시간, 스토리지 및 애플리케이션 로직을 저장, 타임 스탬프를 포함합니다.
Julien

1
부울 및 날짜 필드가 마음에 듭니다. 삭제 논리를 구현하는 방법에 따라 날짜와 "삭제 된"레코드의 고유 키를 보유하는 고유 한 테이블이있을 수도 있습니다. 저장 프로 시저를 통해이를 쉽게 수행 할 수 있습니다. 필요한 행당 추가 공간을 1 비트 대 8+로 줄입니다. 소스 테이블을 건드리지 않고 매일 삭제에 대해보고 할 수도 있습니다.
AndrewSQL

참고 : delete는 MySQL에서 예약어입니다.
Jason Rikard

deleted필드 에서 필터링 된 인덱스는 삭제되지 않은 행을 쿼리 할 때 성능을 크게 향상시킬 수 있습니다.
Ross Presser

21

우리의 응용 프로그램에서 우리는 실제로 사용자 요청에 따라 아무것도 삭제 하지 않습니다 (고객은 무언가를 삭제하면 잠재적으로 법적 문제가 발생할 수있는 규제 된 환경에 있습니다).

이전 버전을 별도의 감사 테이블 (따라서 some_table_audit라는 테이블 인 some_table 테이블)에 추가 버전 식별자 (DB가 시간 값을 충분히 세분화하는 경우 타임 스탬프, 정수 버전 번호)와 동일한 테이블을 유지합니다. 또는 일반 감사 테이블 등에 대한 외래 키인 UUID를 사용하고 트리거에 의해 감사 테이블을 자동으로 업데이트합니다 (따라서 레코드를 업데이트하는 모든 코드를 감사 요구 사항에 알릴 필요는 없습니다).

이 방법:

  • 삭제 작업은 간단한 삭제입니다. 코드를 추가 할 필요가 없습니다 (실제로 삭제되지 않은 행을 삭제하도록 요청한 사람을 기록 할 수는 있음)
  • 삽입과 업데이트는 비슷합니다
  • "일반"행을 이전 버전으로 반환하여 삭제 취소 또는 되돌림을 구현할 수 있습니다 (감사 트리거가 다시 시작되어 감사 추적 테이블에도이 변경 사항이 반영됨)
  • 당신은 마지막 버전을 삭제 취소 할뿐만 아니라 과거 버전을 검토하거나 되돌릴 수있는 기회를 제공 할 수 있습니다
  • "삭제 된 것으로 표시되어 있습니까?"를 추가하지 않아도됩니다. 감사 테이블에서 삭제 된 행으로 수행 할 작업을 결정해야하지만 행을 삭제 / 업데이트하는 모든 코드 포인트에 대해 "감사 사본 업데이트"논리 또는 해당 테이블을 참조하는 모든 코드 포인트를 검사합니다. 레코드가 삭제 된 후 나중에 삭제 취소 된 경우 히스토리에 구멍이 없으므로 각 버전의 플래그가 삭제 / 표시되지 않음)
  • 감사 사본을 별도의 테이블에 보관하면 다른 파일 그룹으로 쉽게 분할 할 수 있습니다.

정수 버전 번호 대신 (또는) 타임 스탬프를 사용하는 경우, 필요한 경우 설정된 시간이 지난 후 오래된 사본을 삭제하는 데 사용할 수 있습니다. 그러나 디스크 공간은 요즘 상대적으로 저렴하므로 오래된 데이터 (예 : X 개월 / 년 후에 클라이언트 데이터를 삭제해야한다는 데이터 보호 규정)를 삭제해야 할 이유가 없다면 그렇지 않습니다.


이 답변은 몇 년 전부터이 계획에 영향을 줄 수있는 몇 가지 주요 사항이 변경되었습니다. 나는 자세히 설명하지는 않지만 오늘 이것을 읽는 사람들의 이익을 위해 간략하게 설명합니다.

  • SQL Server 2016에는이 작업을 많이 수행하는 "시스템 버전 임시 테이블"이 도입되었으며, 역사적인 쿼리를보다 쉽게 ​​구성 및 유지 관리 할 수있는 유용한 구문 설탕이 제공되며 그 사이에 스키마 변경의 하위 집합을 조정합니다. 기본 및 히스토리 테이블. 그들은 경고가 없지만 이러한 종류의 목적을위한 강력한 도구입니다. 다른 DB 시스템에서도 비슷한 기능을 사용할 수 있습니다.

  • 특히 GDPR 도입과 같은 데이터 보호 법률의 변경은 데이터를 하드 삭제해야하는 시점을 크게 변화시킬 수 있습니다. 고려할 때 사람들의 권리를 존중할 필요 (일반적으로 그리고 관련 법규에 명시되어 있음)에 대한 감사 목적으로 나중에 감사 목적으로 유용 할 수있는 (또는 실제로 법적으로 요구되는) 데이터를 삭제하지 않는 균형을 측정해야합니다. 당신의 디자인. 변경 사항을 수행하는 동안 내역 추적을 해제하기 위해 스키마 단기 변경없이 개인 데이터를 제거하기 위해 내역을 수정할 수 없으므로 시스템 버전의 임시 테이블에서 문제가 될 수 있습니다.


열 삭제 및 이름 바꾸기를 어떻게 처리합니까? 모든 것을 nullable로 설정 하시겠습니까?
Stijn

1
@Stijn : 자주 나오지 않도록 구조가 변경되는 것은 아닙니다. Colunms는 일반적으로 프로덕션 환경에 일단 존재하면 제거되지 않습니다. 사용이 중단되면 NULL을 무시하는 제한 조건을 삭제하십시오 (또는 더 더러운 느낌이지만 "매직 값"을 사용하여 제한 조건을 처리하기 위해 기본값을 추가하십시오) 다른 코드에서 참조를 중지하십시오. 이름 바꾸기 : 새로 추가, 이전 사용 중지 및 필요한 경우 이전 데이터를 새 데이터로 복사합니다. 열 이름을 바꾸는 경우 기본 테이블과 감사 테이블이 동시에 동일하게 변경되어야합니다.
David Spillett

9

부울 삭제 된 열을 사용하면 테이블이 커지고 실제로 커지면 문제가 발생하기 시작합니다. 삭제 된 열을 일주일에 한 번 (사양에 따라 다소) 다른 테이블로 이동하는 것이 좋습니다. 그렇게하면 멋진 작은 활성 테이블과 시간이 지남에 따라 수집 된 모든 레코드를 포함하는 큰 테이블이 있습니다.


7

별도의 테이블로 갈 것입니다. Ruby on Rails에는 acts_as_versioned플러그인 이 있으며 , 기본적으로 행을 _version업데이트하기 전에 접미사가있는 다른 테이블에 행을 저장 합니다. 정확한 행동이 필요하지는 않지만 귀하의 경우에 대해서도 작동해야합니다 (삭제하기 전에 복사).

@Spredzy와 마찬가지로 delete_dateX 시간 / 일 / 그 이후로 복원되지 않은 레코드를 프로그래밍 방식으로 제거 할 수 있도록 열을 추가하는 것이 좋습니다 .


4

이 문제에 대해 내부적으로 사용하는 솔루션은 객체의 특정 상태에 대해 하드 코딩 된 값이있는 상태 열 (삭제, 활성, 비활성, 열기, 닫힘, 차단됨)을 갖는 것입니다. 각 상태는 응용 프로그램에서 사용되는 의미입니다. db 관점에서 객체를 제거하지 않고 상태를 변경하고 객체 테이블의 각 변경 기록을 유지합니다.


3

"후자의 솔루션에는 '삭제 된'레코드를 무시하기 위해 추가 애플리케이션 로직이 필요합니다."라고 말할 때 간단한 솔루션은이를 필터링하는보기를 갖는 것입니다.


보기의 문제가 아닙니다. 세트에서 수행되는 모든 작업은 "삭제 된"레코드를 제외해야합니다.
Abie

2

Spredzy가 제안한 것과 유사하게 모든 응용 프로그램에서 삭제하기 위해 타임 스탬프 필드를 사용합니다. 타임 스탬프가 설정되고 레코드가 삭제되었음을 나타내므로 부울은 불필요합니다. 이렇게 AND (deleted IS NULL OR deleted = 0)하면 모델이 명시 적으로 삭제 된 레코드를 포함하도록 요청하지 않는 한 PDO는 항상 select 문에 추가 합니다.

현재 Blob 또는 텍스트가 포함 된 테이블을 제외하고는 가비지 수집하지 않습니다. 레코드가 제대로 정규화되면 공간이 사소한 것이며 deleted필드를 색인화 하면 선택 속도에 대한 영향이 제한됩니다.


0

또는 사용자 (및 개발자)에게 onus를 배치하고 'Are you sure?', 'Are you sure?'의 순서로 진행할 수 있습니다. 그리고 '당신은 전적으로 확실하고 확실합니까?' 기록이 삭제되기 전에 질문. 약간의 면밀하지만 고려할 가치가 있습니다.


0

'DeletedDate'와 같은 열이있는 테이블 행을 보는 데 익숙하지만 마음에 들지 않습니다. '삭제됨'의 개념은 처음부터 항목을 작성해서는 안된다는 것입니다. 실제로 데이터베이스에서 제거 할 수는 없지만 뜨거운 데이터와 함께 사용하고 싶지는 않습니다. 논리적으로 삭제 된 행은 누군가가 특별히 삭제 된 데이터를보고 싶어하지 않는 한 콜드 데이터입니다.

또한 작성된 모든 쿼리는 쿼리를 구체적으로 제외해야하며 인덱스도 고려해야합니다.

내가보고 싶은 것은 데이터베이스 아키텍처 수준과 응용 프로그램 수준에서의 변경입니다. 'deleted'라는 스키마를 만듭니다. 각 사용자 정의 테이블은 메타 데이터를 보유하는 여분의 필드 (테이블을 삭제 한 사용자)와 '삭제 된'스키마에서 동일하게 동일합니다. 외래 키를 만들어야합니다.

다음으로 삭제는 삽입 삭제가됩니다. 먼저 삭제할 행이 '삭제 된'스키마 대응 항목에 삽입됩니다. 그런 다음 기본 테이블에서 해당 행을 삭제할 수 있습니다. 그러나 추가 로직을 라인 어딘가에 추가해야합니다. 외래 키 위반을 처리 할 수 ​​있습니다.

외래 키를 올바르게 처리해야합니다. 행을 논리적으로 삭제했지만 기본 / 고유 행이이를 참조하는 다른 테이블에 열을 갖는 것은 좋지 않습니다. 어쨌든 이런 일은 일어나지 않아야합니다. 정규 작업은 외부 키가 있더라도 기본 테이블에 다른 테이블에서 참조가없는 행을 제거 할 수 있지만 이는 비즈니스 논리입니다.

전반적인 이점은 테이블의 메타 데이터 감소 및 성능 향상입니다. 'deletedDate'열은이 행이 실제로 여기에 있지 않아야하지만 편의상 여기에두고 SQL 쿼리가 처리하도록합니다. 삭제 된 행의 사본이 '삭제 된'스키마에 보관 된 경우 핫 데이터가있는 기본 테이블은 핫 데이터의 비율이 높고 (적시에 아카이브 된 것으로 가정) 불필요한 메타 데이터 열이 줄어 듭니다. 인덱스 및 쿼리는 더 이상이 필드를 고려할 필요가 없습니다. 행 크기가 짧을수록 더 많은 행을 페이지에 맞출 수 있으며 SQL Server가 더 빠르게 작동 할 수 있습니다.

가장 큰 단점은 작업의 크기입니다. 추가 논리 및 오류 처리뿐만 아니라 하나 대신 두 개의 작업이 있습니다. 그렇지 않으면 단일 열을 업데이트하는 것보다 더 많은 잠금이 발생할 수 있습니다. 트랜잭션은 테이블에 대한 잠금을 더 오래 보유하며 두 개의 테이블이 관련됩니다. 적어도 내 경험상 프로덕션 데이터를 삭제하는 것은 거의 이루어지지 않습니다. 그럼에도 불구하고, 주요 테이블 중 하나에서 거의 1 억 개 항목 중 7.5 %가 'DeletedDate'열에 항목이 있습니다.

질문에 대한 답변으로 응용 프로그램은 '삭제 취소'를 알고 있어야합니다. '삭제 된'스키마의 행을 기본 테이블에 삽입 한 다음 '삭제 된 스키마의 행을 삭제하십시오. 오류, 외래 키 문제 등을 피하기 위해 몇 가지 추가 논리 및 오류 처리가 필요합니다.

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