IsDeleted (소프트 삭제)를 강제로 구현할 때 적절한 인덱스 아키텍처는 무엇입니까?


16

현재 모든 기능을 갖춘 기존 데이터베이스 및 응용 프로그램이 있습니다. 현재 아키텍처를 변경할 수 없습니다. 현재 데이터베이스의 각 테이블에는 기본값이 '0'인 "IsDeleted"NOT NULL BIT 필드가 있습니다. 응용 프로그램이 데이터를 "삭제"하면 단순히 IsDeleted 플래그를 1로 업데이트합니다.

내가 이해하는 데 어려움이있는 것은 각 테이블의 인덱스를 구성하는 방법입니다. 현재 모든 쿼리 / 가입 / 등은 항상 IsDeleted 검사를 구현합니다. 개발자가 따라야 할 표준입니다. 즉, 각 테이블의 모든 클러스터 된 기본 키 인덱스를 기본 키와 IsDeleted BIT 필드를 포함하도록 변경해야하는지 확인하려고합니다. 또한 모든 쿼리 / 가입 / 기타 이후. IsDeleted 검사를 구현해야합니다. 모든 단일 인덱스 (비 클러스터형)도 IsDeleted 필드를 인덱스의 첫 번째 필드로 포함해야한다는 적절한 가정입니까?

내가 가진 또 다른 질문은 필터링 된 인덱스에 관한 것입니다. 인덱스 크기를 줄이기 위해 "WHERE IsDeleted = 0"과 같은 인덱스에 필터를 배치 할 수 있음을 이해합니다. 그러나 모든 조인 / 쿼리에서 IsDeleted 검사를 구현해야하므로 필터링 된 인덱스가 사용되지 않습니다 (IsDeleted 열이 조인 / 쿼리에 사용되므로)?

IsDeleted 접근 방식을 변경할 수는 없습니다.

답변:


13

여기서 가장 쉬운 방법은 키와 클러스터형 인덱스를 그대로두고 클러스터되지 않은 인덱스에 필터링 된 인덱스를 사용하는 것입니다.

또한 일부 큰 테이블을 분할 된 힙 또는 분할 된 클러스터 열 저장소 (SQL Server 2016+)로 마이그레이션하여 기본 키와 고유 인덱스를 분할하지 않은 상태로 둘 수 있습니다. 이렇게하면 IsDeleted 행의 키가 아닌 열을 별도의 데이터 구조로 푸시 할 수 있습니다.이 데이터 구조는 추가로 다르게 압축되거나 다른 파일 그룹에 저장 될 수 있습니다.

그리고 개발자가 IsDeleted 행을 필터링하기 위해 매개 변수 대신 리터럴을 사용해야합니다. 매개 변수를 사용하면 SQL Server는 두 경우 모두 동일한 쿼리 계획을 사용해야합니다.

EG

SELECT ... WHERE ... AND IsDeleted=0

그리고 아닙니다 :

SELECT ... WHERE ... AND IsDeleted=@IsDeleted

매개 변수를 사용하면 필터링 된 색인을 사용할 수 없으며 매개 변수 스니핑에 문제가 생길 수 있습니다.


IsDeleted컬럼 의 유비쿼터스와 중요성을 고려할 때 물리적 스토리지에 관계없이 두 가지보기 (선택적으로 다른 스키마)를 통해 데이터를 노출하는 것이 합리적 일 수 있습니다. 가능성이 적습니다. 기본 데이터에 액세스하는 것은 삭제 된 데이터와 삭제되지 않은 데이터를 어떻게 든 결합해야하는 경우와 실제로 행을 "삭제됨"으로 전환해야하는 경우에만 해당됩니다.
Jeroen Mostert

@JeroenMostert 좋은 조언. RLS는 여기 또는 EF Core Global Query Filters와 같은 곳에서도 사용할 수 있습니다. docs.microsoft.com/ko-kr/ef/core/querying/filters
David Browne-Microsoft

9

이것은 인기가없는 의견 일지 모르지만, "모든 곳에서이 작업을 수행"/ 한 가지 크기가 모든 질문에 대한 답변이라고 생각하지 않습니다.

아무 이유없이 많은 IsDeleted 행을 검색하는 쿼리가있는 경우 한 가지 해결 방법은 해당 쿼리를 충족시키기 위해 필터링 된 비 클러스터형 인덱스를 만드는 것입니다.

또 다른 옵션은 삭제되지 않은 행으로 필터링되는 여러 가지 다른 쿼리에서 활용할 수있는 인덱싱 된 뷰를 만드는 것입니다. 이 기능은 Enterprise Edition에서 특히 유용 할 수 있습니다. Enterprise Edition에서는 자동 인덱스보기 일치가NOEXPAND 힌트 .

작은 테이블 또는 많이 읽히는 테이블의 경우 필터링 된 비 클러스터형 인덱스 나 뷰 또는 다른 항목을 추가하면 실제로 데이터베이스에 불필요한 오버 헤드가 추가 될 수 있습니다.


2

삭제가 드물다는 합리적인 가정 하에서 지수에 대한 변경은 적절한 해결책이 아닙니다.

조만간 삭제 된 행에 대한 참조를 쿼리해야하며 색인에있는 행이 갑자기 가치가 있음을 알았습니다.

보기를 사용하지 않으면 필터를 포함하도록 모든 쿼리를 편집해야합니다.


0

IS_DELETED 플래그가 0 또는 PK 값인 시스템을 보았습니다. 다른 시스템에서는 PK의 부정이었습니다.

대부분의 쿼리는 "자연"또는 비즈니스 (때로는 다중 필드) 키로 값을 검색하므로 조인을 통한 경우를 제외하고는 PK에서 쿼리하지 않습니다. 그러나 기본 테이블과 결합 된 테이블의 끝에 항상 AND IS_DELETED = 0을 추가했습니다.

이 시스템에는 변경 사항을 추적 한 모든 트랜잭션 테이블에 대한 감사 테이블도있었습니다. 애플리케이션에는 삭제 된 데이터를 포함하여 모든 데이터 변경 사항을 표시하는 기능이 있습니다.


0

쿼리를 변경할 권리와 능력이 있기를 바랍니다.

그러나 모든 조인 / 쿼리에서 IsDeleted 검사를 구현해야하므로 필터링 된 인덱스가 사용되지 않습니다 (IsDeleted 열이 조인 / 쿼리에 사용되므로)?

한 가지 중요한 점을 말하고 싶었습니다. 설명 할 수 있기를 바랍니다.

where Transaction tableMastertable이 모두 사용 되는 복잡한 쿼리에서 .

테이블 IsDeleted=0에서만 사용하십시오 Transaction. Master테이블 에서 사용하지 마십시오 .

예,

Select * from dbo.Order O
inner join dbo.category C on o.categoryid=o.categoryid
inner join dbo.Product P on P.Productid=o.Productid
where o.isdeleted=0

아무 문제가 없다 c.isdeleted=0의 사용은 (Category 테이블 ). 불필요합니다.

마찬가지로 사용하는 데 어떤 점이 P.isdeleted=0있습니까?

삭제되지 않은 모든 주문과 세부 정보를 원하기 때문입니다.

어떻게 수행 할 수 있습니다 Product때 삭제 될 수 Order있습니다 Active또는 어디든지 Productid참조입니다.

따라서 중요한 쿼리에서 신중하게 디버그하면 isdeleted = 0 중 일부를 제거 할 수 있습니다.

맹목적으로 필터링 된 인덱스를 만들지 말고 먼저 매우 중요하고 느린 쿼리를 모두 선택하십시오.

느린 쿼리를 최적화 한 다음 필터링 된 인덱스 또는 튜닝 인덱스 만 결정하십시오.

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