バックグラウンド
統計オブジェクトのデータは、次の形式のステートメントを使用して収集されます。
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は、乱数ジェネレーターを使用して、ページが修飾されるかどうかを決定します。このインスタンスで使用されるジェネレーターは、以下に示すパラメーター値を持つレーマー乱数ジェネレーターです。
X 次 = X シード * 7 5 MOD(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
上記のクエリ例では、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乱数ジェネレーターを使用した結果の1つは、シード値zeroおよびint.maxを使用しないことです。これにより、アルゴリズムがゼロのシーケンスを生成するようになります(すべてのページを選択)。
コードはゼロを検出し、その場合のシードとしてシステム「クロック」からの値を使用します。種子は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
句に記載されている内容(ゼロパーセントであっても)にかかわらず、すべてのページのすべての行が選択されます。