Remus는 VARCHAR
열의 최대 길이가 예상 행 크기에 영향을 미치므로 SQL Server가 제공하는 메모리 부여에 도움이된다고 지적했습니다 .
나는 그의 대답의 "이것에서 계단식으로"부분을 확장하기 위해 조금 더 많은 연구를 시도했습니다. 나는 완전하거나 간결한 설명이 없지만 여기에 내가 찾은 것이 있습니다.
재현 스크립트
내 컴퓨터에서 VARCHAR(256)
버전 생성 시간이 약 10 배 정도 걸리는 가짜 데이터 세트를 생성 하는 전체 스크립트 를 작성했습니다 . 사용 된 데이터가 정확하게 동일하지만, 제 테이블의 실제 최대 길이를 사용하여 18
, 75
, 9
, 15
, 123
, 및 5
모든 컬럼의 최대 길이를 사용하면서 256
두 번째 테이블.
원래 테이블 키잉
여기에서 원래 쿼리가 약 20 초 안에 완료되고 논리적 읽기가 테이블 크기 ~1.5GB
(195K 페이지, 페이지 당 8K) 와 동일하다는 것을 알 수 있습니다.
-- CPU time = 37674 ms, elapsed time = 19206 ms.
-- Table 'testVarchar'. Scan count 9, logical reads 194490, physical reads 0
CREATE CLUSTERED INDEX IX_testVarchar
ON dbo.testVarchar (s1, s2, s3, s4)
WITH (MAXDOP = 8) -- Same as my global MAXDOP, but just being explicit
GO
VARCHAR (256) 테이블 키잉
를 들어 VARCHAR(256)
테이블, 우리는 경과 시간이 크게 증가했다고 참조하십시오.
흥미롭게도 CPU 시간이나 논리적 읽기가 증가하지 않습니다. 이것은 테이블에 정확히 동일한 데이터가 있지만 경과 시간이 너무 느린 이유를 설명하지는 않습니다.
-- CPU time = 33212 ms, elapsed time = 263134 ms.
-- Table 'testVarchar256'. Scan count 9, logical reads 194491
CREATE CLUSTERED INDEX IX_testVarchar256
ON dbo.testVarchar256 (s1, s2, s3, s4)
WITH (MAXDOP = 8) -- Same as my global MAXDOP, but just being explicit
GO
I / O 및 대기 통계 : 원래
우리가 조금 더 자세하게 ( p_perfMon, 내가 작성한 절차 사용) 캡처하면 대부분의 I / O가 LOG
파일에서 수행되는 것을 볼 수 있습니다. 실제 ROWS
(메인 데이터 파일)에서 I / O의 양이 상대적으로 적 으며 기본 대기 유형은 LATCH_EX
인 메모리 페이지 경합을 나타냅니다.
우리는 또한, 내 회전 디스크 어딘가에 "나쁜"와 "놀랍게도 나쁜"사이 인 것을 알 수있다 폴 랜달에 따라 :)
I / O 및 대기 통계 : VARCHAR (256)
를 들어 VARCHAR(256)
버전의 I / O 및 대기 통계는 완전히 다른 봐! 여기에서 데이터 파일 ( ROWS
) 의 I / O가 크게 증가한 것을 알 수 있으며, 중단 시간으로 인해 Paul Randal은 단순히 "WOW!"라고 말합니다.
# 1 대기 유형이 이제는 놀라운 것은 아닙니다 IO_COMPLETION
. 그러나 왜 이렇게 많은 I / O가 생성됩니까?
실제 쿼리 계획 : VARCHAR (256)
쿼리 계획에서 Sort
운영자는 VARCHAR(256)
쿼리 버전 에서 재귀 유출 (5 레벨 깊이!) 을 볼 수 있습니다. (원본 버전에서는 유출이 전혀 없습니다.)
실시간 쿼리 진행 : VARCHAR (256)
sys.dm_exec_query_profiles를 사용하여 SQL 2014+에서 실시간 쿼리 진행 상황을 볼 수 있습니다 . 원래 버전에서, 전체 Table Scan
및 Sort
모든 유출 (처리없이 spill_page_count
남아 0
걸쳐).
VARCHAR(256)
그러나 버전 에서는 Sort
운영자 에게 페이지 유출이 빠르게 누적되는 것을 볼 수 있습니다 . 다음은 쿼리가 완료되기 직전에 쿼리 진행률에 대한 스냅 샷입니다. 여기의 데이터는 모든 스레드에 걸쳐 집계됩니다.
각 스레드를 개별적으로 파는 경우 2 개의 스레드가 약 5 초 (테이블 스캔에 15 초를 소비 한 후 전체 20 초) 이내에 정렬을 완료합니다. 모든 스레드가이 비율로 진행되면 VARCHAR(256)
인덱스 작성은 원래 테이블과 거의 같은 시간에 완료됩니다.
그러나 나머지 6 개의 스레드는 훨씬 느린 속도로 진행됩니다. 메모리가 할당되는 방식과 스레드가 데이터를 흘릴 때 I / O에 의해 유지되는 방식 때문일 수 있습니다. 그래도 확실하지 않습니다.
당신은 무엇을 할 수 있나요?
시도해 볼만한 것들이 많이 있습니다 :
- 공급 업체와 협력하여 이전 버전으로 롤백하십시오. 이것이 가능하지 않은 경우,이 변경 사항에 만족하지 않는 공급 업체가 향후 릴리스에서 되돌릴 수 있도록하십시오.
- 색인을 추가 할 때 현재 서버 수준 설정보다 낮은 숫자를 사용
OPTION (MAXDOP X)
하는 X
것이 좋습니다. OPTION (MAXDOP 2)
내 컴퓨터 에서이 특정 데이터 세트를 사용 하면 VARCHAR(256)
버전이 완료되었습니다 25 seconds
(8 스레드와 3-4 분 비교)! 유출 동작이 더 높은 병렬 처리로 악화 될 수 있습니다.
- 추가 하드웨어 투자가 필요할 경우 시스템에서 I / O (병목 가능성이 있음)를 프로파일 링하고 유출로 인한 I / O의 대기 시간을 줄이기 위해 SSD 사용을 고려하십시오.
추가 자료
Paul White는 관심이있을만한 SQL Server 내부 에 대한 멋진 블로그 게시물을 보유하고 있습니다. 병렬 정렬에 대한 스 필링, 스레드 왜곡 및 메모리 할당에 대해 조금 이야기합니다.