배경
통계 오브젝트에 대한 데이터는 다음 양식의 명령문을 사용하여 수집됩니다.
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
... 위의 방정식에 표시된대로 시드에 41A7
16 진수 (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 %)의 모든 행을 선택합니다 .