반응형

예상 XML 실행 계획

아래의 예제를 살펴보자.

 

이해를 돕기 위해 앞서 14. 텍스트 및 XML 실행 계획의 기초 - 텍스트 실행 계획 에서 사용하였던 예제를 그대로 사용하였다.

다만, 이번에는 XML 형식으로 예상 실행 계획을 캡처하기 위해 SHOWPLAN_XML 명령어를 실행하였다.

SET SHOWPLAN_XML ON;
GO
 
SELECT c.[LastName],
       a.[City],
       cu.[AccountNumber],
       st.[Name] AS TerritoryName
  FROM [Person].[Contact] c
  JOIN [Sales].[Individual] i
    ON c.[ContactID] = i.[ContactID]
  JOIN [Sales].[CustomerAddress] ca
    ON i.[CustomerID] = ca.[CustomerID]
  JOIN Person.Address a
    ON [ca].[AddressID] = [a].[AddressID]
  JOIN [Sales].Customer cu
    ON cu.[CustomerID] = i.[CustomerID]
  JOIN [Sales].[SalesTerritory] st
    ON [cu].[TerritoryID] = [st].[TerritoryID]
 WHERE st.[Name] = 'Northeast'
   AND a.[StateProvinceID] = 55;
GO
 
SET SHOWPLAN_XML OFF;
GO

 

이제 결과 창에 나타난 XML 문서의 링크를 클릭하자. 그러면 다음과 같이 새로운 탭에서 XML 실행 계획이 표시될 것이다.


 

[그림 1] XML 예상 실행 계획 1

 

그래픽 실행 계획과는 달리 XML 데이터는 한 눈에 쏙 들어오지 않을 것이다.

창 왼쪽을 보면 “+”, “-“ 버튼들이 위치되어 있는데, 각각의 XML element를 접었다 폈다 하면서 해석해 나가도록 하자.

XML 실행 계획 해석에 대한 기본적인 내용은 5. 실행 계획 기초 - XML 실행 계획 사용하기 에서 이미 살펴보았기 때문에 중복되는 내용은 건너뛰도록 하겠다.

 

먼저, BatchSquence > Batch > Statements > StmtSimple element 다음에 위치한 QueryPlan의 물리적인 속성을 보자.

<QueryPlan CachedPlanSize="50" CompileTime="322" CompileCPU="45" CompileMemory="520">

이는 캐시된 실행 계획의 크기와, 컴파일 하는데 얼마나 시간을 소요하였으며 또, CPU와 메모리는 얼마나 사용하였는지를 보여준다.

 

다음으로 MissingIndexes element를 보도록 하자. 여기에는 쿼리 옵티마이저가 실행 계획을 작성할 때 해당 쿼리에 관련하여 누락된 것으로 간주된 인덱스 정보를 보여준다.

<MissingIndexes>
  <MissingIndexGroup Impact="30.8535">
    <MissingIndex Database="[AdventureWorks]" Schema="[Sales]" Table="[CustomerAddress]">
      <ColumnGroup Usage="EQUALITY">
        <Column Name="[AddressID]" ColumnId="2" />
      </ColumnGroup>
      <ColumnGroup Usage="INCLUDE">
        <Column Name="[CustomerID]" ColumnId="1" />
      </ColumnGroup>
    </MissingIndex>
  </MissingIndexGroup>
</MissingIndexes>

 

이어서 RelOP 노드들이 보인다. 이것들은 쿼리 옵티마이저가 연산을 수행하는 동안 예상되는 물리 연산자들을 설명하고 있다. NodeId = 0 는 첫번째 노드로써 가장 마지막 수행된 NestedLoop 연산을 가리킨다.

<RelOp NodeId="0" PhysicalOp="Nested Loops" LogicalOp="Inner Join"
EstimateRows="1.94953" EstimateIO="0" EstimateCPU="6.37415e-005" AvgRowSize="119"
EstimatedTotalSubtreeCost="0.376226" Parallel="0" EstimateRebinds="0"
EstimateRewinds="0">

 

여기에 표시되는 정보들은 마치 그래픽 실행 계획의 ToolTip 창에서 보여지는 것과 유사하다. 텍스트 실행 계획에서는 단순히 EstimateExecutions만 표시되었던 것과는 달리 XML 실행 계획에서는 예상되는 Rebind와 Rewind 수치도 함께 보여주고 있다.

 

다음에 이어지는 element들은 ColumnReference element의 리스트인 OutputList element이다. 이는 SELECT에 의해 반환되는 각각의 컬럼 속성을 나타낸다.

<OutputList>
  <ColumnReference Database="[AdventureWorks]" Schema="[Person]"
     Table="[Contact]" Alias="[c]" Column="LastName" />
  <ColumnReference Database="[AdventureWorks]" Schema="[Person]"
     Table="[Address]" Alias="[a]" Column="City" />
  <ColumnReference Table="[cu]" Column="AccountNumber" ComputedColumn="1" />
  <ColumnReference Database="[AdventureWorks]" Schema="[Sales]"
     Table="[SalesTerritory]" Alias="[st]" Column="Name" />
</OutputList>

부연 설명을 하면, 이는 AdventureWorks 데이터베이스의 Person 스키마의 (Alias가 c인) Contact 테이블에서는 LastName 컬럼을, (Alias가 a인) Address 테이블에서는 City 컬럼을, 그리고 Sales 스키마의 (Alias 가 st인) Sales 테이블에서는 Name 컬럼에서 결과를 가져옴을 의미한다. 물론 그래픽 실행 계획의 속성 창 및 ToolTip 에서도 이 내용을 확인할 수 있다.

 

마지막으로 설명할 내용은 Node 0의 OutputList 아래에 위치하고 있는 Nested Loop 연산이다. 여기에서는 Nested Loop 연산에 참여하고 있는 테이블 및 컬럼 정보 등을 확인할 수 있다.

<NestedLoops Optimized="0">
  <OuterReferences>
    <ColumnReference Database="[AdventureWorks]" Schema="[Sales]" Table="[Customer]"
       Alias="[cu]" Column="TerritoryID" />
  </OuterReferences>

 

 

실질 XML 실행 계획

위(예상 XML 실행 계획)에서 사용한 쿼리를 다시 한 번 실행해 보도록 하자. 이번에는 실질 실행 계획을 캡쳐하기 위해 STATISTICS XML 명령어를 사용하겠다.

SET STATISTICS XML ON;
GO
 
SELECT c.[LastName],
       a.[City],
       cu.[AccountNumber],
       st.[Name] AS TerritoryName
  FROM [Person].[Contact] c
  JOIN [Sales].[Individual] i
    ON c.[ContactID] = i.[ContactID]
  JOIN [Sales].[CustomerAddress] ca
    ON i.[CustomerID] = ca.[CustomerID]
  JOIN Person.Address a
    ON [ca].[AddressID] = [a].[AddressID]
  JOIN [Sales].Customer cu
    ON cu.[CustomerID] = i.[CustomerID]
  JOIN [Sales].[SalesTerritory] st
    ON [cu].[TerritoryID] = [st].[TerritoryID]
 WHERE st.[Name] = 'Northeast'
   AND a.[StateProvinceID] = 55 ;
GO
 
SET STATISTICS XML OFF;
GO

 

이제 실질 실행 계획을 살펴보자.

먼저, QueryPlan element 부분에 DegreeOfParallelism과 쿼리를 실행할 때 필요한 메모리 양을 의미하는 MemoryGrant가 추가적으로 보여짐을 확인할 수 있다.

<QueryPlan DegreeOfParallelism="0" MemoryGrant="82" CachedPlanSize="57"
CompileTime="29293" CompileCPU="6277" CompileMemory="520">

 

예상 XML 실행 계획과 실질 XML 실행 계획의 가장 큰 차이점은 누가 뭐래도 RunTimeInformation element이다. 말 그대로 쿼리가 실제로 실행되었을 때의 런타임 정보로써 Thread, 실제 행 수, 실제 실행 회수를 확인할 수 있다.

<RunTimeInformation>
  <RunTimeCountersPerThread Thread="0" ActualRows="4" ActualEndOfScans="1"
    ActualExecutions="1" />
</RunTimeInformation>
<NestedLoops Optimized="0">

 

 

다음 이야기: 16. 저장 프로시저에서의 실행 계획

반응형

+ Recent posts