情報
私の質問は、ヒープである適度に大きなテーブル(約40GBのデータ領域)に関するものです
(残念ながら、アプリケーションの所有者はテーブルにクラスター化インデックスを追加できません)
Identity列(ID
)に自動作成された統計が作成されましたが、空です。
実際の質問
私の理解では、まったく同じ列(重複)に2つの統計がある場合でも、すべての統計を使用でき、変更が追跡されるので、なぜこの統計が空のままなのですか?
統計情報
DB stat info
テーブルサイズ
統計が作成される列情報
[ID] [int] IDENTITY(1,1) NOT NULL
ID列
select * from sys.stats
where name like '%_WA_Sys_0000000A_6B7099F3%';
別の統計に関する情報を取得しています
select * From sys.dm_db_stats_properties (1802541555, 3)
私の空の統計と比較して:
「生成スクリプト」からの統計+ヒストグラム:
/****** Object: Statistic [_WA_Sys_0000000A_6B7099F3] Script Date: 2/1/2019 10:18:19 AM ******/
CREATE STATISTICS [_WA_Sys_0000000A_6B7099F3] ON [dbo].[table]([ID]) WITH STATS_STREAM = 0x01000000010000000000000000000000EC03686B0000000040000000000000000000000000000000380348063800000004000A00000000000000000000000000
統計のコピーを作成するときに、内部にデータがありません
CREATE STATISTICS [_WA_Sys_0000000A_6B7099F3_TEST] ON [dbo].[table]([ID]) WITH STATS_STREAM = 0x01000000010000000000000000000000EC03686B0000000040000000000000000000000000000000380348063800000004000A00000000000000000000000000
統計を手動で更新すると、更新されます
UPDATE STATISTICS [dbo].[Table]([_WA_Sys_0000000A_6B7099F3_TEST])
空の統計情報と入力された統計情報の両方を使用して、これを再現できました。空のテーブルに自動統計が作成されるように手配しましたが、インデックスは後で作成されました。
IF OBJECT_ID(N'dbo.Heap', N'U') IS NOT NULL
BEGIN
DROP TABLE dbo.Heap;
END;
GO
CREATE TABLE dbo.Heap
(
id integer NOT NULL IDENTITY,
val integer NOT NULL,
);
GO
-- Add 1000 rows
INSERT dbo.Heap
WITH (TABLOCKX)
(val)
SELECT
SV.number
FROM master.dbo.spt_values AS SV
WHERE
SV.[type] = N'P'
AND SV.number BETWEEN 1 AND 1000;
GO
SELECT COUNT_BIG(*)
FROM dbo.Heap AS H
JOIN dbo.Heap AS H2
ON H2.id = H.id
WHERE H.id > 0
AND H2.id > 0;
GO
-- Empty table
TRUNCATE TABLE dbo.Heap;
GO
-- Repeat exact same query (RT = 500 + 0.2 * 1000 = 700)
GO
SELECT COUNT_BIG(*)
FROM dbo.Heap AS H
JOIN dbo.Heap AS H2
ON H2.id = H.id
WHERE H.id > 0
AND H2.id > 0;
GO
-- Add 1000 rows
INSERT dbo.Heap
WITH (TABLOCKX)
(val)
SELECT
SV.number
FROM master.dbo.spt_values AS SV
WHERE
SV.[type] = N'P'
AND SV.number BETWEEN 1 AND 1000;
GO
-- Add index
ALTER TABLE dbo.Heap ADD
CONSTRAINT [PK dbo.Heap id]
PRIMARY KEY NONCLUSTERED (id);
GO
SELECT
S.[name],
S.auto_created,
DDSP.stats_id,
DDSP.last_updated,
DDSP.[rows],
DDSP.rows_sampled,
DDSP.steps,
DDSP.unfiltered_rows,
DDSP.modification_counter
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.Heap', N'U');
空ではないすべての重複で変更が引き続き正確に追跡されていることがわかりましたが、(非同期設定に関係なく)自動的に更新される統計は1つだけです。
自動統計更新は、クエリオプティマイザーが特定の統計を必要とし、それが古くなっている(最適性関連の再コンパイル)場合にのみ発生します。
オプティマイザは SQL Server 2012のキャッシュと再コンパイルの計画 ペーパーで説明されているように、重複した統計から選択します。
このドキュメントのトピックに直接関係のない問題は、同じ列セットの同じ順序で複数の統計情報が与えられた場合、クエリオプティマイザーはクエリ最適化中にロードするものをどのように決定するのですか?答えは単純ではありませんが、クエリオプティマイザは次のようなガイドラインを使用します。古い統計よりも最近の統計を優先する。サンプリングを使用して計算されたものよりも、
FULLSCAN
オプションを使用して計算された統計を優先します。等々。
重要なのは、オプティマイザが利用可能な重複統計(「最良のもの」)からoneを選択し、その統計が古くなっている場合は自動的に更新されることです。
これは古いリリースからの動作の変更であると思います。または、少なくともドキュメントでは、オブジェクトのすべての古い統計がこのプロセスの一部として更新されることを示唆していますが、いつ変更されたかはわかりません。 Matt Bowlerが Duplicate Statistics を投稿したのは2013年8月以降でした。これには、便利なAdventureWorksベースのリポジトリが含まれています。このスクリプトにより、統計オブジェクトの1つだけが更新されましたが、当時は両方が更新されていました。
上記の説明は、シナリオを再現しようとしたときに観察したすべての動作と一致しますが、どこかに明示的に記載されているとは思えません。複製を完全に更新しておく価値はほとんどないため、これは賢明な最適化のように見えます。
これはおそらく、Microsoftがサポートしようとしているレベルよりも詳細です。これは、予告なく変更される可能性があることも意味します。