반응형

Insert, Update, Delete문의 실행 계획

 

 

 

드디어, 그래픽 실행 계획의 기초 마지막 이야기이다. 지금까지 우리는 SELECT문에 대해서만 살펴보았다. 이번 포스트에서는 다른 DML , INSERT, UPDATE 그리고 DELETE문의 실행 계획을 살펴 보도록 하겠다.

 

 

 

Insert문

 

먼저, 아래와 같이  간단한 INSERT문을 작성해 보자.

 

INSERT INTO [AdventureWorks].[Person].[Address]
(
[AddressLine1],
[AddressLine2],
[City],
[StateProvinceID],
[PostalCode],
[rowguid],
[ModifiedDate]
)
VALUES (
'1313 Mockingbird Lane',
'Basement',
'Springfield',
'79',
'02134',
NEWID(),
GETDATE()
) ;

 

이 쿼리의 실행 계획은 다음과 같다.

 


[그림 1] INSERT문의 실행 계획

 

가장 먼저 보이는 것은 Constant Scan 연산자이다. 이 연산자는 입력(INSERT)할 상수 행을 작성하여 쿼리에 전달한다. 그 뒤로 Constant Scan 연산자에 의해 생성된 행에 열을 추가하기 위해 두 개의 Compute Scalar 연산자가 따라오고 있다. 이 예제의 경우, NEWID()로 생성된 uniqueidentifierGETDATE()로 부터 얻은 날짜 값을 행에 추가하고 있다.

 

생성된 행은 Clustered Index Insert 연산자를 통과한다. 이 연산자가 가장 많은 비용을 사용하고 있다. 이 때, INSERT문으로 부터 얻어진 출력 값은 [Person].[Address].[StateProvinceId]이다.

 

이어지는 연산은 Nested Loop Join 이다. [Person].[StateProvince] 테이블을 Clustered Index Seek 연산한 결과와 Join하고 있다. 이는 StateProvinceId 컬럼의 참조 무결성을 체크하기 위함이다. 참조 무결성의 실질적인 체크는 이어서 보이는 Assert 연산자가 수행한다. Assert 연산자는 참조 무결성 뿐만 아니라, 기타 제약 조건 및 스칼라 하위 쿼리의 유효성 검사도 한다. Assert 연산자가 계산한 식이 NULL이면 Assert 연산자를 통과하여 쿼리 실행을 계속하고,  이 식이 NULL이 아니면 해당 오류를 발생시킨다.

 

 

 

Update문

 

아래와 같은 UPDATE문을 작성해 보자.

 

UPDATE [Person].[Address]
SET [City] = 'Munro',
[ModifiedDate] = GETDATE()
WHERE [City] = 'Monroe' ;

 

이 쿼리의 예상 실행 계획은 다음과 같다.

 


 

[그림 2] UPDATE문의 실행 계획

그럼, 실행 계획을 살펴보도록 하자. 

 

가장 먼저 실행되는 것은 Non-clustered Index Scan 이다. 이 연산자는 이 쿼리에서 UPDATE할 대상 행을 조회하고 있다. 즉, WHERE [City] = 'Monroe' 조건에 해당하는 행을 조회하여 연산 결과를 다음에 이어지는 TOP 연산자에게 전달한다. TOP 연산자는 UPDATE할 행 수를 제한한다. 하지만, 이 쿼리의 경우 UPDATE문에 TOP 구문을 기술하지 않았으므로 행을 제한하지 않는다.

 

다음으로 보이는 것은 Eager Spool 연산자이다. 이 연산자는 Table Spool의 한 형태로써, UPDATE할 각 행을 tempdb 데이터베이스에 저장된 숨겨진 임시 개체에 저장한다. 이는 Nested Loops 연산자 등으로 연산자를 rewind를 할 경우, 다시 바인딩할(rebind) 필요가 없다면 데이터를 다시 스캔하는 대신 -여기서는 Non-clustered Index Scan을 반복하는 것을 의미한다. - 스풀된 데이터를 재사용하기 위함이다.  하지만 다시 바인딩을 해야 하는 경우에는 이미 스풀된 데이터를 삭제하고 다시 검색하여 스풀 개체를 다시 작성한다.

 

이어지는 연산자는 Compute Scalar 연산자 3개이다. 여기서는 GETDATE() 함수와 같이 쿼리 내의 Scalar 값을 계산하고 있다.

마지막으로 UPDATE문의 가장 핵심적인 부분인 Clustered Index Update 연산을 하고 있다. 이 예제의 경우 Clustered Index의 한 부분을 갱신하고 있으므로 Clustered Index Update 연산을 통해 갱신할 행을 식별하고 해당 행을 갱신한다.

 

성능적인 이슈를 살펴보면, 갱신할 행을 어떻게 검색을 하느냐?가 가장 중요하다. 이 예제의 경우, Non-clustered Index Scan을 하고 있다. 앞서 설명하였다시피 이 연산은 효율적이지 못하다. 예제의 경우 16개의 행을 갱신하기 위해 19615행에 대해 Non-clustered Index 전체를 읽어야만 한다. 따라서 Clustered Index SeekNon-Clustered Index Seek를 유도하는 것이 바람직할 것이다.

 

 

 

Delete문

 

DELETE문에서는 어떤 실행 계획이 만들어 질까? 아래의 쿼리를 작성한 실행 계획을 살펴보도록 하자.

 

DELETE FROM [Person].[Address]
WHERE [AddressID] = 52;

 


[그림 3] DELETE문의 실행 계획

 

실행 계획을 살펴보자. 언제나 그렇듯이 오른쪽에서 시작하여 위에서 아래로

 

가장 먼저 실행되는 것은 Clustered Index Delete 연산자이다

우리는 여기서 다른 DML문에서의 실행 계획에서는 없었던 재미있는 사실, 두 가지를 확인할 있다.

번째는  DELETE 연산이 프로세스의 부분에서 실행되고 있다는 것이고,

번째는 Clustered Index Delete 연산의 Seek Predicate :

Prefix: [AdventureWorks].[Person].[Address].AddressID = Scalar

Operator(CONVERT_IMPLICIT(int,[@1],0)).

이다.

@1 파라미터는 [AddressId] 의미한다. 우리는 파라미터를 사용한 적이 없다. 단지, [AddressId] 상수 값으로 52 제공한 것 뿐이었다. 그렇다면 파라미터는 도대체 어디에서 것인가?

 

이는 실행 계획의 재사용을 목적으로 Realtional Engine 쿼리를 재작성(simple parameterization)하였기 때문이다.

이것은 마치,

 

DELETE FROM [Person].[Address]
WHERE [AddressID] = @1;

 

같이 앞으로 [AddressId] 어떤 값이 바인딩되던간에 같은 실행 계획을 사용할 수 있도록 SQL Server 알아서 쿼리를 재구성한 것이다. 어떤가? 정말 똑똑하지 않은가?

 


[그림 4] DELETE문의 실행 계획 - Clustered Index Delete

 

DELETE 후 Nested Loop Join 연산을 통해 일련의 Index Seek, Clustered Index Seek, Cluastered Index Scan 연산 결과가 결합하고 있다. 특히 여기서는 Left Semi Join을 하고 있다. 그리고 마지막으로 각 Join 연산으로 부터 얻어진 결과 값을 Assert 연산자에 통과시키고 있다. 이는 앞서 설명하였듯이 삭제하고자 하는 데이터와 관련된 모든 테이블에 대해 참조 무결성을 체크하기 위함이다.

 


[그림 5] DELETE문의 실행 계획 - Assert 

 

 

요약

 

지금까지 우리는 그래픽 실행 계획을 해석하는 방법을 살펴보았다. 특히 수십여 개의 실행 계획 중에서 가장 많이 사용되는 것들 중심으로 아주 단순한 쿼리를 통해 살펴보았다. 물론 지금까지의 내용을숙지하였다고 해서 지금 당장 수십, 수백 라인에 이르는 복잡한 쿼리의 실행 계획을 순식간에 해석할 수는 없을 것이다. 하지만 연습보다 훌륭한 선생이 없다. 실행 계획을 꾸준히 읽고 해석하는 연습을 반복하다가 보면 언젠가는 ! 하지 않을까?

 

 

 

다음 이야기 : 14 텍스트 및 XML 실행 계획의 기초 - 텍스트 실행 계획

반응형

+ Recent posts