통계 업데이트를위한 표본 크기의 이상한 동작


25

SQL Server (2012)의 통계 업데이트로 샘플링 임계 값을 조사하는 중이었고 흥미로운 행동을 발견했습니다. 기본적으로 샘플링 된 행 수는 동일한 데이터 집합을 사용하는 경우에도 일부 상황에서 다른 것으로 보입니다.

이 쿼리를 실행합니다.

--Drop table if exists
IF (OBJECT_ID('dbo.Test')) IS NOT NULL DROP TABLE dbo.Test;

--Create Table for Testing
CREATE TABLE dbo.Test(Id INT IDENTITY(1,1) CONSTRAINT PK_Test PRIMARY KEY CLUSTERED, TextValue VARCHAR(20) NULL);

--Insert enough data so we have more than 8Mb (the threshold at which sampling kicks in)
INSERT INTO dbo.Test(TextValue) 
SELECT TOP 1000000 'blahblahblah'
FROM sys.objects a, sys.objects b, sys.objects c, sys.objects d;  

--Create Index on TextValue
CREATE INDEX IX_Test_TextValue ON dbo.Test(TextValue);

--Update Statistics without specifying how many rows to sample
UPDATE STATISTICS dbo.Test IX_Test_TextValue;

--View the Statistics
DBCC SHOW_STATISTICS('dbo.Test', IX_Test_TextValue) WITH STAT_HEADER;

SHOW_STATISTICS의 출력을 보면 "행이 샘플링 됨"이 각 전체 실행에 따라 다릅니다 (즉, 테이블이 삭제, 재 작성 및 다시 채워짐).

예를 들면 다음과 같습니다.

샘플링 된 행

  • 318618
  • 319240
  • 324198
  • 314154

나는이 수치가 테이블이 동일 할 때마다 동일 할 것이라고 기대했다. 그건 그렇고, 데이터를 삭제하고 다시 삽입하면이 동작이 발생하지 않습니다.

중요한 질문은 아니지만 무슨 일이 일어나고 있는지 이해하고 싶습니다.


2
파일 그룹에 얼마나 많은 파일을 삽입하고 있습니까? 나는 2016 년에 몇 번을 시도하고 두 번 테이블은 두 개의 서로 다른 샘플 314,712 및 315,270이었다 I 톱 크기 (64)와 함께 3584 개 279 행 페이지 1로 분할했다 - 279 모두 정확한 배수
마틴 스미스

1
@JoeObbish-항상 AFAIK 전체 페이지를 읽으므로 놀라지 않았습니다. 어떤 이유로 나는 질문의 숫자가 그 패턴과 일치하지 않는다고 생각했습니다. 그러나 그들이하는 수학을 다시하는 것. 318618 = 1142*279, 319240 = 1144*279 + 64, 324198=1162*279314154=1126이렇게 분산 샘플링 페이지의 수입니다.
Martin Smith

@MartinSmith 단 하나의 파일-279 숫자는 흥미 롭습니다. 저는 항상 관련된 패턴을 이해하고 싶습니다.
Matthew McGiffen

답변:


26

배경

통계 오브젝트에 대한 데이터는 다음 양식의 명령문을 사용하여 수집됩니다.

SELECT 
    StatMan([SC0], [SC1], [SB0000]) 
FROM 
(
    SELECT TOP 100 PERCENT 
        [SC0], [SC1], STEP_DIRECTION([SC0]) OVER (ORDER BY NULL) AS [SB0000]
    FROM 
    (
        SELECT 
            [TextValue] AS [SC0], 
            [Id] AS [SC1] 
        FROM [dbo].[Test] 
            TABLESAMPLE SYSTEM (2.223684e+001 PERCENT) 
            WITH (READUNCOMMITTED) 
    ) AS _MS_UPDSTATS_TBL_HELPER 
    ORDER BY 
        [SC0], 
        [SC1], 
        [SB0000] 
) AS _MS_UPDSTATS_TBL
OPTION (MAXDOP 1)

확장 이벤트 또는 프로파일 러 ( SP:StmtCompleted)를 사용하여이 명령문을 수집 할 수 있습니다 .

통계 생성 쿼리는 종종 비 클러스터형 인덱스 페이지가 아닌 기본 테이블에 액세스하여 비 클러스터형 인덱스 페이지에서 자연스럽게 발생하는 값의 클러스터링을 피합니다.

샘플링 된 행 수는 샘플링을 위해 선택한 전체 페이지 수에 따라 다릅니다. 테이블의 각 페이지가 선택되었거나 선택되지 않았습니다. 선택된 페이지의 모든 행이 통계에 기여합니다.

난수

SQL Server는 난수 생성기를 사용하여 페이지의 자격 여부를 결정합니다. 이 인스턴스에 사용 된 생성기 는 아래와 같이 매개 변수 값을 가진 Lehmer 난수 생성기 입니다.

X 다음 = X 시드 * 7 5 모드 (2 31-1 )

의 값은 다음의 합으로 계산됩니다.Xseed

  • 제 (의 낮은 정수 부분 bigint) 기본 테이블의 partition_id

    SELECT
        P.[partition_id] & 0xFFFFFFFF
    FROM sys.partitions AS P
    WHERE
        P.[object_id] = OBJECT_ID(N'dbo.Test', N'U')
        AND P.index_id = 1;
    
  • REPEATABLE절에 지정된 값

    • sampled UPDATE STATISTICS의 경우 REPEATABLE값은 1입니다.
    • 이 값은 m_randomSeed추적 플래그 8666이 활성화 된 경우 실행 계획에 표시되는 액세스 방법의 내부 디버깅 정보 요소에 표시됩니다 (예 :<Field FieldName="m_randomSeed" FieldValue="1" />

SQL Server 2012의 경우이 계산은 다음에서 수행됩니다 sqlmin!UnOrderPageScanner::StartScan.

mov     edx,dword ptr [rcx+30h]
add     edx,dword ptr [rcx+2Ch]

여기서 at 메모리 [rcx+30h]는 파티션 ID의 하위 32 비트를 [rcx+2Ch]포함하고 at 메모리 REPEATABLE는 사용중인 값 을 포함합니다 .

난수 생성기는 나중에 같은 메소드에서 초기화되어을 호출 sqlmin!RandomNumGenerator::Init합니다.

imul    r9d,r9d,41A7h

... 위의 방정식에 표시된대로 시드에 41A716 진수 (16807 10 진수 = 7 5 )를 곱합니다 .

나중의 임의의 숫자 (개별 페이지의 경우)는에 삽입 된 동일한 기본 코드를 사용하여 생성됩니다 sqlmin!UnOrderPageScanner::SetupSubScanner.

StatMan

StatMan위에 표시된 예제 쿼리의 경우 T-SQL 문과 동일한 페이지가 수집됩니다.

SELECT 
    COUNT_BIG(*) 
FROM dbo.Test AS T 
    TABLESAMPLE SYSTEM (2.223684e+001 PERCENT)  -- Same sample %
    REPEATABLE (1)                              -- Always 1 for statman
    WITH (INDEX(0));                            -- Scan base object

이것은 다음의 출력과 일치합니다.

SELECT 
    DDSP.rows_sampled
FROM sys.stats AS S
CROSS APPLY sys.dm_db_stats_properties(S.[object_id], S.stats_id) AS DDSP
WHERE 
    S.[object_id] = OBJECT_ID(N'dbo.Test', N'U')
    AND S.[name] = N'IX_Test_TextValue';

가장자리 케이스

MINSTD Lehmer 난수 생성기를 사용하면 시드 값이 0 및 int.max를 사용하지 않아야합니다. 이로 인해 알고리즘에서 일련의 0이 생성됩니다 (모든 페이지 선택).

이 코드는 0을 감지하고 시스템 'clock'의 값을 시드로 사용합니다. 시드가 int.max ( 0x7FFFFFFF= 2 31-1 ) 인 경우 동일하지 않습니다 .

초기 시드는 파티션 ID의 하위 32 비트와 REPEATABLE값 의 합으로 계산되므로이 시나리오를 엔지니어링 할 수 있습니다 . REPEATABLE샘플 int.max이기 때문에, 모든 페이지 인 시드 될 것이다 값이 선택된다 :

SELECT
    0x7FFFFFFF - (P.[partition_id] & 0xFFFFFFFF)
FROM sys.partitions AS P
WHERE
    P.[object_id] = OBJECT_ID(N'dbo.Test', N'U')
    AND P.index_id = 1;

완전한 예제로 작업하기 :

DECLARE @SQL nvarchar(4000) = 
    N'
    SELECT
        COUNT_BIG(*) 
    FROM dbo.Test AS T 
        TABLESAMPLE (0 PERCENT) 
        REPEATABLE (' +
        (
            SELECT TOP (1)
                CONVERT(nvarchar(11), 0x7FFFFFFF - P.[partition_id] & 0xFFFFFFFF)
            FROM sys.partitions AS P
            WHERE
                P.[object_id] = OBJECT_ID(N'dbo.Test', N'U')
                AND P.index_id = 1
        ) + ')
        WITH (INDEX(0));';

PRINT @SQL;
--EXECUTE (@SQL);

TABLESAMPLE조항이 말하는 모든 페이지 (모든 0 %)의 모든 행을 선택합니다 .


11

이것은 훌륭한 질문입니다! 나는 내가 아는 것으로 시작한 다음 추측으로 넘어갈 것이다. 내 블로그 게시물 여기 에 이것에 대한 자세한 내용이 있습니다 .

샘플링 된 통계 업데이트는 TABLESAMPLE뒤에서 사용 됩니다. 온라인에 대한 문서를 찾는 것은 매우 쉽습니다. 그러나, 반환 된 행 이 객체의 TABLESAMPLE부분에 의존 한다는 것은 잘 알려져 있지 않습니다 hobt_id. 객체를 삭제하고 다시 만들면 hobt_id무작위 샘플링으로 반환되는 행이 달라 지므로 새로운 객체를 얻게 됩니다.

데이터를 삭제하고 다시 삽입 hobt_id하면 동일하게 유지됩니다. 데이터가 디스크에 동일한 방식으로 배치되어있는 경우 (할당 순서 스캔에서 동일한 결과를 동일한 순서로 반환) 샘플링 된 데이터는 변경되지 않아야합니다.

테이블에서 클러스터형 인덱스를 다시 작성하여 샘플링 된 행 수를 변경할 수도 있습니다. 예를 들면 다음과 같습니다.

UPDATE STATISTICS dbo.Test IX_Test_TextValue;

DBCC SHOW_STATISTICS('dbo.Test', IX_Test_TextValue) WITH STAT_HEADER; -- 273862 rows

ALTER INDEX PK_Test on Test REBUILD;

UPDATE STATISTICS dbo.Test IX_Test_TextValue;

DBCC SHOW_STATISTICS('dbo.Test', IX_Test_TextValue) WITH STAT_HEADER; -- 273320 rows

그 이유는 SQL Server가 인덱스에서 샘플링 된 통계를 수집 할 때 비 클러스터형 인덱스 대신 클러스터형 인덱스를 검색하기 때문이라고 생각합니다. 또한 대한이 (숨겨진 통계 업데이트 쿼리를 추적 우리에게) 값을 숨김가 있다는 생각 REPEATABLE과 함께 사용 TABLESAMPLE. 나는 그 중 어느 것도 입증하지 못했지만, 클러스터 된 인덱스를 다시 작성하여 히스토그램과 행이 샘플링 된 이유를 설명합니다.


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