2016-07-23 1 views
2

수백만 개의 레코드가있는 부모 테이블과 부모 테이블의 기본 키를 가리키는 외래 키가있는 자식 테이블 세 개가 있습니다. 그래서 같이 :SQL Server의 여러 테이블에서 많은 레코드를 삭제하는 모범 사례

Parent 
parent_id (PK) \  Child1 
       |  child1_id (PK) 
       |---- parent_id (FK) 
       | 
       |  Child2 
       |  child2_id (PK) 
       |---- parent_id (FK) 
       | 
       |  Child3 
       |  child3_id (PK) 
       |---- parent_id (FK) 

은 무엇 하드에 가장 좋은 방법은 Parent에서 수백 수천 개의 레코드의 삭제 있을까? 다음 조건에서 삭제하고 싶습니다 : DELETE FROM PARENT WHERE [STATUS] = 'DONE'. 삭제가 진행되는 동안 테이블을 잠그지 않는 방법이 있습니까? 그래서 다른 레코드를 모든 테이블에 삽입 할 수 있습니까? 내가 생각할 수있는 옵션 : 외부 키에

  1. 사용 CASCADE DELETE.
  2. 소프트 삭제 사용 : 트랜잭션 UPDATE parent SET [DELETED] = 1 WHERE [STATUS] = 'DONE'을 시작하고 해당 상위 ID로 각 하위를 삭제 한 다음 상위를 하드 삭제하고 커밋하십시오.
  3. 2.와 비슷하지만 프로 시저를 사용하여 삭제할 ID를 테이블 변수에 저장하므로 Parent 테이블에 새로운 [DELETED] 열을 추가 할 필요가 없습니다.
  4. 삭제할 ID를 선택하십시오. SELECT parent_id FROM parent WHERE [STATUS] = 'DONE' 그런 다음이 모든 ID를 전달하는 일괄 삭제를 수행하십시오. (이것은 정말로 나쁘게 수행합니다, 그래서 나는 그것을 버리고 있습니다).

SQL Server 2014 및 spring jdbc를 사용하고 있습니다.

+1

외래 키에 대해 계단식 삭제를 사용하고 매회 최대 50,000 개의 레코드를 삭제하는 것이 좋습니다. 대다수의 레코드를 삭제하면 대개 작은 배치로 분할 할 때 속도가 빨라집니다. –

+1

저는 작업 진행 상황을 측정하는 팬이기 때문에 작은 부분으로 레코드를 제거하는 절차를 작성하는 것이 좋습니다. ON CASCADE DELETE로 가거나 직접하십시오. –

답변

1

나는 각 자식 테이블 그래서 TOP X

를 사용하여 일괄 적으로 삭제하는 것을 선호 : 각 자식 테이블에 대한

DELETE TOP 10000 
FROM child1 
FROM child 1 as c1 
INNER join parent 
On parent_Id = c1.parent_id 
AND parent.[STATUS] = 'DONE' 

반복 여러 배치를.

주기적으로 자식이없는 상위 레코드를 제거 할 수 있습니다.

DELETE TOP 10000 
FROM parent 
FROM parent as p 
Left outer join child1 c1 
On p.parent_Id = c1.parent_id 
AND c1.child_id IS NULL 
Left outer join child2 c2 
On p.parent_Id = c2.parent_id 
AND c2.child_id IS NULL 
Left outer join child3 c3 
On p.parent_Id = c3.parent_id 
AND c3.child_id IS NULL 
WHERE parent.[STATUS] = 'DONE' 

각 부모는 부모가 삭제 실행 빈도를 결정합니다 얼마나 많은 아이들. 당신은 물론 다양 할 수 있습니다. X를 작게 테스트 한 후 50000이라고 말합니다.

+0

'TOP 10000 ... WHERE parent. [STATUS] ='DONE '은 새로운'DONE '레코드가 삽입 될 수 있기 때문에 삭제할 수 없으므로 삭제할 수 없습니다. 테이블 변수 나 임시 테이블에서 삭제할 모든 레코드의 ID를 저장 한 다음 제안한대로 배치에서 삭제할 수 있습니다. – otonakav

+1

Where 문에 날짜로 제한하거나 ID로 정렬하여 이전 레코드 만 제거되도록하는 방법은 무엇입니까? – Mike

+0

좋은 감사합니다. – otonakav

1

삭제가 진행되는 동안 테이블을 잠그지 않는 방법이 있습니까?

예. 제안한 바와 같이 수백만 개의 레코드 대신 한 번에 일괄 적으로 운영하면 동시 액세스가 향상됩니다.

계단식 삭제는 결코 교활하지 않기 때문에 절대로 사용하지 않습니다. 수작업으로 작동하지만 수백만 개가 춥습니다. 비논리적이기 때문에 TOP 항목을 사용하지 않습니다. 데이터의 일부 측면 대신 임의의 번호로 작동합니다.

이와 같은 절차를 작성할 때마다 동일한 기술을 사용했습니다. 하단에서 시작하여 루프는 기본 키를 따라 데이터의 하위 집합을 삭제합니다. delete가 영향을받은 행이 0 개를 반환하면 맨 위 행을 삭제하고 매달린 참조를 남기지 않을 때까지 다음 테이블로 이동합니다. 그에 한 번에 하나의 parent_id에 대한 모든 행을 삭제할 수없는 경우, 성능 향상을 위해 일부 제한 집합을 찾을

while @nrows > 0 begin 
    delete from Child3 
    where -- limitation criteria -- and 
    parent_id = (
     select min(parent_id) 
     from Parent 
     where Status = 'DONE' 
    ) 
    set @nrows = @@rowcount 
done 

, 루프 : 기본 삭제는 다음과 같이 보인다.아마 날짜, 그리고 한 번에 한 달 또는 한 년을 제거하십시오. 한 번에 둘 이상의 부모를 삭제할 수있는 경우 한 번에 하위 집합을 선택하고 최소값 대신 exists을 사용하십시오.

다행히도 이러한 목적으로 사용자 정의 트랜잭션이 필요하지 않습니다. 어쨌든 행은 토스트가되며 'DONE'상위 항목이 있는지 여부에 상관없이 언제 어디서든지 다시 시작할 수 있습니다.

관련 문제