스파 스 열, CPU 시간 및 필터링 된 인덱스


10

스파링

스파 스 열에 대해 몇 가지 테스트를 수행 할 때 직접적인 원인을 알고 싶은 성능 저하가있었습니다.

DDL

하나는 4 개의 희소 열이 있고 다른 하나는 희소 열이없는 두 개의 동일한 테이블을 만들었습니다.

--Non Sparse columns table & NC index
CREATE TABLE dbo.nonsparse( ID INT IDENTITY(1,1) PRIMARY KEY NOT NULL,
                      charval char(20) NULL,
                      varcharval varchar(20) NULL,
                      intval int NULL,
                      bigintval bigint NULL
                      );
CREATE INDEX IX_Nonsparse_intval_varcharval
ON dbo.nonsparse(intval,varcharval)
INCLUDE(bigintval,charval);

-- sparse columns table & NC index

CREATE TABLE dbo.sparse( ID INT IDENTITY(1,1) PRIMARY KEY NOT NULL,
                      charval char(20) SPARSE NULL ,
                      varcharval varchar(20) SPARSE NULL,
                      intval int SPARSE NULL,
                      bigintval bigint SPARSE NULL
                      );

CREATE INDEX IX_sparse_intval_varcharval
ON dbo.sparse(intval,varcharval)
INCLUDE(bigintval,charval);

DML

그런 다음 약 2540 NON-NULL 값을 둘 다에 삽입했습니다.

INSERT INTO dbo.nonsparse WITH(TABLOCK) (charval, varcharval,intval,bigintval)
SELECT 'Val1','Val2',20,19
FROM MASTER..spt_values;

INSERT INTO dbo.sparse WITH(TABLOCK) (charval, varcharval,intval,bigintval)
SELECT 'Val1','Val2',20,19
FROM MASTER..spt_values;

그런 다음 두 테이블에 1M NULL 값을 삽입했습니다.

INSERT INTO dbo.nonsparse WITH(TABLOCK)  (charval, varcharval,intval,bigintval)
SELECT TOP(1000000) NULL,NULL,NULL,NULL 
FROM MASTER..spt_values spt1
CROSS APPLY MASTER..spt_values spt2;

INSERT INTO dbo.sparse WITH(TABLOCK) (charval, varcharval,intval,bigintval)
SELECT TOP(1000000) NULL,NULL,NULL,NULL 
FROM MASTER..spt_values spt1
CROSS APPLY MASTER..spt_values spt2;

쿼리

스파 스가 아닌 테이블 실행

새로 작성된 비 분산 테이블에서이 조회를 두 번 실행할 때 다음을 수행하십시오.

SET STATISTICS IO, TIME ON;
SELECT  * FROM dbo.nonsparse
WHERE   1= (SELECT 1) -- force non trivial plan
OPTION(RECOMPILE,MAXDOP 1);

논리적 읽기는 5257 페이지를 보여줍니다.

(1002540 rows affected)
Table 'nonsparse'. Scan count 1, logical reads 5257, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

그리고 CPU 시간은 343ms입니다

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

스파 스 테이블 실행

스파 스 테이블에서 동일한 쿼리를 두 번 실행합니다.

SELECT  * FROM dbo.sparse
WHERE   1= (SELECT 1) -- force non trivial plan
OPTION(RECOMPILE,MAXDOP 1);

더 낮은 1763

(1002540 rows affected)
Table 'sparse'. Scan count 1, logical reads 1763, physical reads 3, read-ahead reads 1759, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

그러나 CPU 시간은 547ms 입니다.

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

스파 스 테이블 실행 계획

스파 스가 아닌 테이블 실행 계획


질문

원래 질문

때문에 NULL의 값이 스파 스 열에 직접 저장되지 않으며, CPU 시간의 증가는 복귀로 인해 수 NULL의 결과 집합으로 값을? 아니면 설명서에 명시된대로 동작 입니까?

스파 스 열은 널이 아닌 값을 검색하기 위해 더 많은 오버 헤드 비용으로 널값에 필요한 공간을 줄입니다.

아니면 오버 헤드가 사용 된 읽기 및 스토리지에만 관련되어 있습니까?

실행 후 폐기 결과로 ssms를 실행하는 경우에도 스파 스 선택의 CPU 시간은 스파 스가 아닌 (219ms)에 비해 더 높습니다 (407ms).

편집하다

2540 만 존재하더라도 null이 아닌 값의 오버 헤드 일 수 있지만 여전히 확신하지 못합니다.

이것은 거의 같은 성능으로 보이지만 드문 요소는 손실되었습니다.

CREATE INDEX IX_Filtered
ON dbo.sparse(charval,varcharval,intval,bigintval)
WHERE charval IS NULL  
      AND varcharval IS NULL
      AND intval  IS NULL
      AND bigintval  IS NULL;

CREATE INDEX IX_Filtered
ON dbo.nonsparse(charval,varcharval,intval,bigintval)
WHERE charval IS NULL  
      AND varcharval IS NULL
      AND intval  IS NULL
      AND bigintval  IS NULL;


    SET STATISTICS IO, TIME ON;

SELECT  charval,varcharval,intval,bigintval FROM dbo.sparse WITH(INDEX(IX_Filtered))
WHERE charval IS NULL AND  varcharval IS NULL
                     AND intval  IS NULL
                     AND bigintval  IS NULL
                     OPTION(RECOMPILE,MAXDOP 1);


SELECT  charval,varcharval,intval,bigintval 
FROM dbo.nonsparse WITH(INDEX(IX_Filtered))
WHERE charval IS NULL AND 
                      varcharval IS NULL
                     AND intval  IS NULL
                     AND bigintval  IS NULL
                     OPTION(RECOMPILE,MAXDOP 1);

대략 같은 실행 시간이있는 것 같습니다 :

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

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

그런데 왜 논리 읽기가 같은 양입니까? 스파 스 열에 대해 필터링 된 인덱스가 포함 된 ID 필드와 다른 비 데이터 페이지를 제외하고 아무것도 저장하지 않아야합니까?

Table 'sparse'. Scan count 1, logical reads 5785,
Table 'nonsparse'. Scan count 1, logical reads 5785

그리고 두 지수의 크기 :

RowCounts   Used_MB Unused_MB   Total_MB
1000000     45.20   0.06        45.26

왜 같은 크기입니까? 희소성이 손실 되었습니까?

필터링 된 인덱스를 사용할 때 두 쿼리 계획


추가 정보

select @@version

Windows Server 2012 R2 Datacenter 6.3의 Microsoft SQL Server 2017 (RTM-CU16) (KB4508218)-14.0.3223.3 (X64) Jul 12 2019 17:43:08 Copyright (C) 2017 Microsoft Corporation Developer Edition (64 비트) 9600 :) (하이퍼 바이저)

쿼리를 실행하고 ID 필드 만 선택하는 동안 희소 테이블에 대한 논리적 읽기가 낮아 CPU 시간이 비슷합니다.

테이블 크기

SchemaName  TableName   RowCounts   Used_MB Unused_MB   Total_MB
dbo         nonsparse   1002540     89.54   0.10        89.64
dbo         sparse      1002540     27.95   0.20        28.14

클러스터형 또는 비 클러스터형 인덱스를 강제 실행하면 CPU 시간 차이가 유지됩니다.


1
편집 후 쿼리에 대한 계획을 얻을 수 있습니까?
George.Palacios

1
@ George.Palacios은 :)을 추가
랜디 Vertongen

답변:


6

아니면 단순히 문서에 명시된대로 작동합니까?

그런 것 같아. 설명서에 언급 된 "오버 헤드"는 CPU 오버 헤드 인 것으로 보입니다.

두 쿼리를 프로파일 링 할 때 스파 스 쿼리는 367ms의 CPU를 샘플링 한 반면 스파 스가 아닌 경우 284ms의 CPU를 사용했습니다. 83ms의 차이입니다.

쿼리를 실행 한 스레드의 총 CPU를 보여주는 Perfview 스크린 샷

그것의 대부분은 어디에 있습니까?

두 프로필은 모두 도착할 때까지 매우 비슷하게 보입니다 sqlmin!IndexDataSetSession::GetNextRowValuesInternal. 이 시점에서 스파 스 코드는 실행 경로를 따라 가며 sqlmin!IndexDataSetSession::GetDataLong, 스파 스 열 기능 ( HasSparseVector, StoreColumnValue) 과 관련이 있고 최대 (42 + 11 =) 53ms를 추가 하는 것처럼 보이는 일부 함수를 호출 합니다.

스파 스 열의 CPU 차이 스크린 샷

왜 같은 크기입니까? 희소성이 손실 되었습니까?

예. 스파 스 열을 인덱스 키로 사용하면 스파 스 스토리지 최적화가 비 클러스터형 인덱스로 전달되지 않는 것으로 보입니다. 따라서 비 클러스터형 인덱스 키 열은 sparseness와 상관없이 전체 크기를 차지하지만 포함 된 열은 희소하고 NULL 인 경우 공간을 0으로 차지합니다.

DBCC PAGENULL 값의 스파 스 열이있는 클러스터형 인덱스 페이지의 출력을 보면 레코드 길이가 11 (ID의 경우 4 + 표준 레코드 당 오버 헤드의 경우 7)임을 알 수 있습니다.

Record Type = PRIMARY_RECORD        Record Attributes =  NULL_BITMAP    Record Size = 11

필터링 된 인덱스의 경우 레코드는 항상 40이며 이는 모든 키 열의 크기의 합계입니다 (4 바이트 ID + 20 바이트 문자 + 4 바이트 varcharval + 4 바이트 intval + 8 바이트 큰 intval = 40 바이트).

어떤 이유로 DBCC PAGE인덱스 레코드의 "레코드 크기"에 7 바이트 오버 헤드가 포함되지 않습니다.

Record Type = INDEX_RECORD          Record Attributes =  NULL_BITMAP    Record Size = 40

필터링되지 않은 인덱스 크기는 더 작습니다 (4 바이트 ID + 4 바이트 intval + 4 바이트 varcharval = 12 바이트). 스파 스 열 중 두 개가 포함 된 열이기 때문에 다시 최적화를 얻습니다.

Record Type = INDEX_RECORD          Record Attributes =  NULL_BITMAP    Record Size = 12

이 동작의 차이점이 문서 페이지에 나열된 제한 중 하나와 일치한다고 생각합니다.

희소 열은 클러스터형 인덱스 또는 고유 한 기본 키 인덱스의 일부일 수 없습니다.

비 클러스터형 인덱스에서는 키가 될 수 있지만 드물게 저장되지는 ​​않습니다.


2
좋은 것! 다시 감사합니다!
Randi Vertongen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.