SQL Server는 둘 이상의 행에 영향을 미치거나 영향을 줄 수있는 업데이트의 일부로 고유 인덱스 를 유지 관리 할 때 항상 연산자의 분할, 정렬 및 축소 조합을 사용합니다 .
문제의 예를 통해 업데이트를 존재하는 네 개의 행 각각에 대해 별도의 단일 행 업데이트로 작성할 수 있습니다.
-- Per row updates
UPDATE dbo.Banana SET pk = 2 WHERE pk = 1;
UPDATE dbo.Banana SET pk = 3 WHERE pk = 2;
UPDATE dbo.Banana SET pk = 4 WHERE pk = 3;
UPDATE dbo.Banana SET pk = 5 WHERE pk = 4;
문제는 첫 번째 문이 pk
1에서 2로 바뀌고 이미 pk
= 2 인 행이 있기 때문에 실패한다는 것입니다 . SQL Server 저장소 엔진은 단일 문 내에서도 모든 처리 단계에서 고유 인덱스를 고유하게 유지해야합니다. . 분할, 정렬 및 축소로 해결 된 문제입니다.
스플릿
첫 번째 단계는 각 update 문을 delete와 insert로 나누는 것입니다.
DELETE dbo.Banana WHERE pk = 1;
INSERT dbo.Banana (pk, c1, c2) VALUES (2, 'A', 'W');
DELETE dbo.Banana WHERE pk = 2;
INSERT dbo.Banana (pk, c1, c2) VALUES (3, 'B', 'X');
DELETE dbo.Banana WHERE pk = 3;
INSERT dbo.Banana (pk, c1, c2) VALUES (4, 'C', 'Y');
DELETE dbo.Banana WHERE pk = 4;
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z');
Split 연산자는 액션 코드 열을 스트림에 추가합니다 (여기서는 Act1007로 표시됨).
조치 코드는 업데이트의 경우 1, 삭제의 경우 3, 삽입의 경우 4입니다.
종류
위의 split 문은 여전히 잘못된 임시 고유 키 위반을 생성하므로 다음 단계는 업데이트되는 고유 인덱스의 키 ( pk
이 경우)와 작업 코드별로 명령문을 정렬하는 것 입니다. 이 예제에서 이는 단순히 동일한 키에서 삭제 (3)가 삽입 (4) 전에 순서화됨을 의미합니다. 결과 순서는 다음과 같습니다.
-- Sort (pk, action)
DELETE dbo.Banana WHERE pk = 1;
DELETE dbo.Banana WHERE pk = 2;
INSERT dbo.Banana (pk, c1, c2) VALUES (2, 'A', 'W');
DELETE dbo.Banana WHERE pk = 3;
INSERT dbo.Banana (pk, c1, c2) VALUES (3, 'B', 'X');
DELETE dbo.Banana WHERE pk = 4;
INSERT dbo.Banana (pk, c1, c2) VALUES (4, 'C', 'Y');
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z');
무너짐
이전 단계는 모든 경우에 허위 고유 위반을 방지하기에 충분합니다. 최적화로서, Collapse는 인접한 삭제와 동일한 키 값에 대한 삽입 을 업데이트에 결합합니다.
-- Collapse (pk)
DELETE dbo.Banana WHERE pk = 1;
UPDATE dbo.Banana SET c1 = 'A', c2 = 'W' WHERE pk = 2;
UPDATE dbo.Banana SET c1 = 'B', c2 = 'X' WHERE pk = 3;
UPDATE dbo.Banana SET c1 = 'C', c2 = 'Y' WHERE pk = 4;
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z');
pk
값 2, 3 및 4에 대한 삭제 / 삽입 쌍이 업데이트로 결합되어 단일 삭제는 pk
= 1이고 삽입은 pk
= 5입니다.
접기 연산자는 키 열을 기준으로 행을 그룹화하고 축소 결과를 반영하도록 조치 코드를 업데이트합니다.
클러스터형 인덱스 업데이트
이 연산자는 업데이트로 표시되어 있지만 삽입, 업데이트 및 삭제할 수 있습니다. 행당 클러스터형 인덱스 업데이트가 수행하는 작업은 해당 행의 작업 코드 값에 따라 결정됩니다. 연산자에는이 작업 모드를 반영하기위한 Action 속성이 있습니다.
행 수정 카운터
위의 세 가지 업데이트 는 유지 관리되는 고유 인덱스 의 키를 수정하지 않습니다 . 실제로 인덱스 의 키 열에 대한 업데이트를 키 가 아닌 열 ( c1
및 c2
)의 업데이트 와 삭제 및 삽입으로 변환했습니다. 삭제 나 삽입으로 잘못된 고유 키 위반이 발생할 수 없습니다.
삽입 또는 삭제는 행의 모든 단일 열에 영향을 미치므로 모든 열과 관련된 통계는 수정 카운터가 증가합니다. 업데이트의 경우 업데이트 된 열이 선행 열로 값이 변경되지 않은 경우에도 수정 카운터가 증가합니다.
따라서 통계 행 수정 카운터 pk
는 c1
및에 대한 2 개의 변경 사항 과 5의 변경 사항을 표시합니다 c2
.
-- Collapse (pk)
DELETE dbo.Banana WHERE pk = 1; -- All columns modified
UPDATE dbo.Banana SET c1 = 'A', c2 = 'W' WHERE pk = 2; -- c1 and c2 modified
UPDATE dbo.Banana SET c1 = 'B', c2 = 'X' WHERE pk = 3; -- c1 and c2 modified
UPDATE dbo.Banana SET c1 = 'C', c2 = 'Y' WHERE pk = 4; -- c1 and c2 modified
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z'); -- All columns modified
참고 : 기본 개체에 적용된 변경 사항 만 (힙 또는 클러스터형 인덱스)에 통계 행 수정 카운터에 영향을줍니다. 비 클러스터형 인덱스는 기본 개체에 대한 변경 내용을 반영하여 보조 구조입니다. 통계 행 수정 카운터에는 전혀 영향을 미치지 않습니다.
개체에 여러 개의 고유 인덱스가있는 경우 별도의 분할, 정렬, 축소 조합을 사용하여 각각에 대한 업데이트를 구성합니다. SQL Server는 Split 결과를 Eager Table Spool에 저장 한 다음 각 고유 인덱스에 대해 해당 세트를 재생합니다 (이는 고유 한 인덱스 키별 정렬 코드 + 작업 코드 및 축소).
통계 업데이트에 대한 영향
쿼리 최적화 프로그램에 통계 정보가 필요하고 기존 통계가 오래 되었거나 스키마 변경으로 인해 유효하지 않은 경우 자동 통계 업데이트 (사용 가능한 경우)가 발생합니다 . 기록 된 수정 수가 임계 값을 초과하면 통계가 오래된 것으로 간주됩니다.
Split / Sort / Collapse 배열은 결과가 다릅니다 은 예상 한 행 수정이 기록되게합니다. 이는 통계 업데이트가 다른 경우보다 조만간 트리거 될 수 있음을 의미합니다.
위의 예에서 키 열의 행 수정은 4 (영향을받는 각 테이블 행에 대해 하나씩) 또는 5 (축소에 의해 생성 된 각 삭제 / 업데이트 / 삽입에 대해)가 아니라 2 (순 변경)만큼 증가합니다.
또한 원래 쿼리에 의해 논리적으로 변경되지 않은 키가 아닌 열은 행 수정을 누적 하여 업데이트 된 테이블 행의 두 배 (각 삭제에 대해 하나씩, 각 삽입에 대해 하나씩)를 가질 수 있습니다 .
기록 된 변경 수는 이전 키 열 값과 새 키 열 값의 겹침 정도에 따라 달라집니다 (따라서 별도의 삭제 및 삽입이 축소 될 수있는 정도). 각 실행간에 테이블을 재설정하면 다음 쿼리는 서로 다른 겹침으로 행 수정 카운터에 미치는 영향을 보여줍니다.
UPDATE dbo.Banana SET pk = pk + 0; -- Full overlap
UPDATE dbo.Banana SET pk = pk + 1;
UPDATE dbo.Banana SET pk = pk + 2;
UPDATE dbo.Banana SET pk = pk + 3;
UPDATE dbo.Banana SET pk = pk + 4; -- No overlap