UAT 및 PROD 서버의 실행 계획 차이


39

UAT (3 초 실행)와 PROD (23 초 실행)에서 동일한 쿼리를 실행하는 데 왜 그렇게 큰 차이가 있는지 이해하고 싶습니다.

UAT와 PROD는 모두 정확하게 데이터와 인덱스를 가지고 있습니다.

질문:

set statistics io on;
set statistics time on;

SELECT CONF_NO,
       'DE',
       'Duplicate Email Address ''' + RTRIM(EMAIL_ADDRESS) + ''' in Maintenance',
       CONF_TARGET_NO
FROM   CONF_TARGET ct
WHERE  CONF_NO = 161
       AND LEFT(INTERNET_USER_ID, 6) != 'ICONF-'
       AND ( ( REGISTRATION_TYPE = 'I'
               AND (SELECT COUNT(1)
                    FROM   PORTFOLIO
                    WHERE  EMAIL_ADDRESS = ct.EMAIL_ADDRESS
                           AND DEACTIVATED_YN = 'N') > 1 )
              OR ( REGISTRATION_TYPE = 'K'
                   AND (SELECT COUNT(1)
                        FROM   CAPITAL_MARKET
                        WHERE  EMAIL_ADDRESS = ct.EMAIL_ADDRESS
                               AND DEACTIVATED_YN = 'N') > 1 ) ) 

UAT에 :

SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 11 ms, elapsed time = 11 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

(3 row(s) affected)
Table 'Worktable'. Scan count 256, logical reads 1304616, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'PORTFOLIO'. Scan count 1, logical reads 84761, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'CAPITAL_MARKET'. Scan count 256, logical reads 9472, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'CONF_TARGET'. Scan count 1, logical reads 100, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 2418 ms,  elapsed time = 2442 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

여기에 이미지 설명을 입력하십시오

PROD :

SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

(3 row(s) affected)
Table 'PORTFOLIO'. Scan count 256, logical reads 21698816, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'CAPITAL_MARKET'. Scan count 256, logical reads 9472, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'CONF_TARGET'. Scan count 1, logical reads 100, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 23937 ms,  elapsed time = 23935 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

여기에 이미지 설명을 입력하십시오

PROD에서 쿼리는 누락 된 인덱스를 제안하며 테스트 한 결과 도움이되지만 토론의 요지는 아닙니다.

ON UAT-왜 SQL Server가 작업자 테이블을 만들고 PROD에서 그렇지 않습니까? PROD가 아닌 UAT에 테이블 스풀을 작성합니다. 또한 UAT와 PROD의 실행 시간이 다른 이유는 무엇입니까?

노트 :

두 서버에서 SQL Server 2008 R2 RTM을 실행하고 있습니다 (곧 최신 SP로 패치 예정).

UAT : 최대 메모리 8GB. MaxDop, 프로세서 선호도 및 최대 작업자 스레드는 0입니다.

Logical to Physical Processor Map:
*-------  Physical Processor 0
-*------  Physical Processor 1
--*-----  Physical Processor 2
---*----  Physical Processor 3
----*---  Physical Processor 4
-----*--  Physical Processor 5
------*-  Physical Processor 6
-------*  Physical Processor 7

Logical Processor to Socket Map:
****----  Socket 0
----****  Socket 1

Logical Processor to NUMA Node Map:
********  NUMA Node 0

PROD : 최대 메모리 60GB. MaxDop, 프로세서 선호도 및 최대 작업자 스레드는 0입니다.

Logical to Physical Processor Map:
**--------------  Physical Processor 0 (Hyperthreaded)
--**------------  Physical Processor 1 (Hyperthreaded)
----**----------  Physical Processor 2 (Hyperthreaded)
------**--------  Physical Processor 3 (Hyperthreaded)
--------**------  Physical Processor 4 (Hyperthreaded)
----------**----  Physical Processor 5 (Hyperthreaded)
------------**--  Physical Processor 6 (Hyperthreaded)
--------------**  Physical Processor 7 (Hyperthreaded)

Logical Processor to Socket Map:
********--------  Socket 0
--------********  Socket 1

Logical Processor to NUMA Node Map:
********--------  NUMA Node 0
--------********  NUMA Node 1

업데이트 :

UAT 실행 계획 XML :

http://pastebin.com/z0PWvw8m

PROD 실행 계획 XML :

http://pastebin.com/GWTY16YY

UAT 실행 계획 XML-PROD에서 생성 된 계획 :

http://pastebin.com/74u3Ntr0

서버 구성 :

PROD : PowerEdge R720xd-Intel (R) Xeon (R) CPU E5-2637 v2 @ 3.50GHz.

UAT : PowerEdge 2950-Intel (R) Xeon (R) CPU X5460 @ 3.16GHz

answers.sqlperformance.com에 게시했습니다


업데이트 :

제안 해 주신 @swasheck에게 감사합니다

PROD의 최대 메모리를 60GB에서 7680MB로 변경하면 PROD에서 동일한 계획을 생성 할 수 있습니다. 쿼리는 UAT와 동시에 완료됩니다.

이제 이해가 필요합니다-왜? 또한, 이것으로, 나는이 몬스터 서버를 이전 서버를 대체하도록 정당화 할 수 없습니다!

답변:


43

버퍼 풀의 잠재적 크기는 여러 가지 방법으로 쿼리 최적화 프로그램의 계획 선택에 영향을줍니다. 내가 아는 한, 하이퍼 스레딩은 계획 선택에 영향을 미치지 않습니다 (잠재적으로 사용 가능한 스케줄러의 수는 확실합니다).

작업 공간 메모리

정렬 및 해시와 같은 메모리 소비 반복기가 포함 된 계획의 경우 버퍼 풀의 크기 (다른 것들 중에서)는 런타임에 쿼리에 사용할 수있는 최대 메모리 부여 량을 결정합니다.

SQL Server 2012 (모든 버전)에서이 숫자는 쿼리 계획의 루트 노드에서 Optimizer Hardware Dependencies섹션으로 보고됩니다 (예 :) Estimated Available Memory Grant. 2012 이전의 버전은 쇼 계획에서이 숫자를보고하지 않습니다.

사용 가능한 예상 메모리 부여는 쿼리 최적화 프로그램이 사용하는 비용 모델에 대한 입력입니다. 결과적으로 큰 정렬 또는 해싱 작업이 필요한 계획 대안은 설정이 낮은 시스템보다 버퍼 풀 설정이 큰 시스템에서 선택 될 가능성이 높습니다. 매우 많은 양의 메모리 가있는 설치의 경우 대체 전략이 선호되는 매우 큰 종류 또는 해시가있는 계획을 선택하면 비용 모델이 이러한 종류의 사고로 너무 멀리 갈 수 있습니다 ( KB2413549-많은 양의 메모리를 사용하면 비효율적 인 SQL Server 계획-TF2335 ).

작업 공간 메모리 부여는 귀하의 경우 요소가 아니지만 알아야 할 가치가 있습니다.

데이터 접근

버퍼 풀의 잠재적 크기는 데이터 액세스에 대한 옵티마이 저의 비용 모델에도 영향을줍니다. 이 모델에서 가정 중 하나는 모든 쿼리가 콜드 캐시로 시작한다는 것입니다. 따라서 페이지에 대한 첫 번째 액세스는 물리적 I / O가 발생한다고 가정합니다. 이 모델은 반복 된 액세스가 다른 것들 중에서 버퍼 풀의 잠재적 크기에 의존하는 요소 인 캐시에서 올 가능성을 고려합니다.

질문에 표시된 쿼리 계획의 클러스터형 인덱스 스캔은 반복 액세스의 한 예입니다. 중첩 루프 세미 조인의 각 반복에 대해 스캔이 다시 감겨집니다 (상관 된 매개 변수의 변경없이 반복됨). 세미 조인에 대한 외부 입력은 28.7874 개의 행을 추정하고 이러한 스캔에 대한 쿼리 계획 속성은 27.7874의 예상 되감기를 결과적으로 보여줍니다.

다시, SQL 서버 2012 만, 계획의 루트 반복자의 수를 보여줍니다 Estimated Pages CachedOptimizer Hardware Dependencies절을 참조하십시오. 이 숫자는 캐시에서 페이지 액세스가 반복 될 가능성을 고려하여 원가 계산 알고리즘에 입력 중 하나를보고합니다.

그 결과 구성되는 최대 버퍼 풀 크기가 더 큰 설치는 더 작은 최대 버퍼 풀 크기가있는 설치보다 동일한 페이지를 두 번 이상 읽는 스캔 비용 (또는 검색)을 줄이는 경향이 있습니다.

간단한 계획에서 되감기 스캔 비용 절감 (estimated number of executions) * (estimated CPU + estimated I/O)은 예상 운영자 비용과 비교 하여 확인할 수 있습니다 . 세미 조인과 노조의 영향으로 인해 예제 계획에서 계산이 더 복잡합니다.

그럼에도 불구하고 문제의 계획은 스캔을 반복하고 임시 색인을 작성하는 것 사이의 선택이 아주 잘 균형 잡힌 경우를 보여줍니다. 더 큰 버퍼 풀이있는 머신에서 스캔 반복은 색인 작성보다 약간 저렴합니다. 버퍼 풀이 더 작은 시스템에서는 스캔 비용이 더 적어 지므로 인덱스 스풀 계획이 옵티 마이저보다 약간 저렴합니다.

계획 선택

옵티마이 저의 비용 모델은 여러 가지 가정을하고 수많은 세부 계산을 포함합니다. 필요한 모든 숫자가 노출되는 것은 아니며 알고리즘이 릴리스마다 변경 될 수 있기 때문에 모든 세부 사항을 항상 따르는 것이 항상 가능하지는 않습니다. 특히, 캐시 된 페이지가 발생할 가능성을 고려하여 적용되는 스케일링 공식은 잘 알려져 있지 않습니다.

이 특별한 경우에, 옵티마이 저의 계획 선택은 어쨌든 잘못된 숫자를 기반으로합니다. Clustered Index Seek의 예상 행 수는 28.7874이지만 런타임시 256 개의 행이 발생합니다. 28.7874 행 내에서 예상되는 값 분포에 대한 옵티마이 저가 가지고있는 정보를 직접 볼 수는 없지만 끔찍하게 잘못되었을 가능성이 큽니다.

추정치가 잘못되면 계획 선택 및 런타임 성능이 본질적으로 우연이 아닙니다. 인덱스 스풀 계획은 어떻게 스캔을 반복보다 더 잘 수행 할 수 있지만, 버퍼 풀의 크기를 증가하는 것은 기형의 원인이라고 생각하는 것은 매우 잘못된 것입니다.

옵티마이 저가 올바른 정보를 가지고 있으면 적절한 실행 계획을 생성 할 가능성이 훨씬 더 좋습니다. 메모리가 더 많은 인스턴스는 일반적으로 메모리가 적은 다른 인스턴스보다 워크로드에서 더 잘 수행되지만 특히 계획 선택이 잘못된 데이터를 기반으로하는 경우에는 보장 할 수 없습니다.

두 인스턴스 모두 고유 한 방식으로 누락 된 인덱스를 제안했습니다. 하나는 명시 적으로 누락 된 인덱스를보고하고 다른 하나는 동일한 특성을 갖는 인덱스 스풀을 사용했습니다. 인덱스가 우수한 성능과 계획 안정성을 제공하면 충분할 수 있습니다. 내 성향은 쿼리를 다시 작성하는 것이지만 아마도 다른 이야기 일 것입니다.


18

Paul White 는 메모리가 더 많은 서버에서 실행할 때 SQL Server 동작의 배후에있는 이유를 명쾌하게 설명했습니다.

또한 문제를 처음 발견 한 @swasheck 에게 큰 감사를드립니다 .

Microsoft에서 사례를 열었으며 제안 된 사항은 다음과 같습니다.

추적 플래그 T2335를 시작 매개 변수로 사용하여 문제점을 해결합니다.

KB2413549 - SQL 서버에 많은 양의 메모리를 사용은 비효율적 인 계획이 발생할 수 있습니다 자세한 내용에 대해 설명합니다.

이 추적 플래그는 SQL Server가 쿼리 실행시 메모리 소비 측면에서보다 보수적 인 계획을 생성하게합니다. SQL Server가 사용할 수있는 메모리 양을 제한하지 않습니다. SQL Server 용으로 구성된 메모리는 여전히 데이터 캐시, 쿼리 실행 및 기타 소비자가 사용합니다. 이 옵션을 프로덕션 환경으로 롤링하기 전에 철저히 테스트하십시오.


13

최대 메모리 설정과 하이퍼 스레딩은 모두 계획 선택에 영향을 줄 수 있습니다.

또한 귀하의 "설정"옵션은 각 환경마다 다릅니다.

UAT의 StatementSetOptions :

ANSI_NULLS="true" 
ANSI_PADDING="true" 
ANSI_WARNINGS="true" 
ARITHABORT="true" 
CONCAT_NULL_YIELDS_NULL="true" 
NUMERIC_ROUNDABORT="false" 
QUOTED_IDENTIFIER="true" 

제품에 대한 StatementSetOptions :

ANSI_NULLS="true" 
ANSI_PADDING="true" 
ANSI_WARNINGS="true" 
ARITHABORT="false" 
CONCAT_NULL_YIELDS_NULL="true"
NUMERIC_ROUNDABORT="false"
QUOTED_IDENTIFIER="true" 

SQL은 SET 옵션에 따라 다른 계획을 생성 할 수 있습니다. 다른 SSMS 세션 또는 앱의 다른 실행에서 계획을 캡처하는 경우에 자주 발생합니다.

개발자가 일관된 연결 문자열을 사용하고 있는지 확인하십시오.


2
Max Memory 및 Hyperthreading이 계획 캐시에 영향을 줄 수 있다고 말한 것은 맞지만 이것이 왜, 왜 발생했는지에 대해 자세히 알고 싶습니다. 답을 부탁드립니다.
Kin Shah

2
Amanda가 말했듯이 SET 옵션이 ARITHABORT와 다른 경우 dba.stackexchange.com/questions/9840/…을
ARA
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.