この列で自動作成された統計が空になるのはなぜですか?


8

情報

私の質問は、ヒープである適度に大きなテーブル(約40GBのデータスペース)に関するもの
です(残念ながら、アプリケーションの所有者はテーブルにクラスター化インデックスを追加できません)

ID列(ID)に自動作成された統計が作成されましたが、空です。

  • 統計の自動作成と統計の自動更新がオンになっています
  • テーブルで変更が行われました
  • 更新されている他の(自動作成された)統計があります
  • インデックスによって作成された同じ列に別の統計があります(重複)
  • ビルド:12.0.5546

重複する統計が更新されています: ここに画像の説明を入力してください

実際の質問

私の理解では、まったく同じ列(重複)に2つの統計がある場合でも、すべての統計を使用でき、変更が追跡されるので、なぜこの統計が空のままなのですか?

統計情報

ここに画像の説明を入力してください

DB統計情報

ここに画像の説明を入力してください

テーブルサイズ

ここに画像の説明を入力してください

統計が作成される列情報

ここに画像の説明を入力してください

[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])

ここに画像の説明を入力してください

回答:


9

空の統計情報と入力された統計情報の両方を使用して、これを再現できました。空のテーブルに自動統計が作成されるように手配しましたが、インデックスは後で作成されました。

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サンプリングを使用して計算されたものより、オプションを使用して計算された統計を優先します。等々。

ポイントは、オプティマイザが選択するということで1利用可能複製統計の(「最良のもの)、および陳腐であることが判明した場合、その一つが自動的に更新されます。

これは以前のリリースからの動作の変更だと思います。または、少なくともドキュメントでは、オブジェクトのすべての古い統計がこのプロセスの一部として更新されることを示唆していますが、いつ変更されたかはわかりません。マットボウラーがDuplicate Statisticsを投稿したのは2013年8月以降でした。これには、便利なAdventureWorksベースのリポジトリが含まれています。このスクリプトにより、統計オブジェクトの1つだけが更新されましたが、当時は両方が更新されていました。

上記の説明は、シナリオを再現しようとしたときに観察したすべての動作と一致しますが、どこかに明示的に記載されているとは思えません。複製を完全に更新しておく価値はほとんどないため、これは賢明な最適化のように見えます。

これはおそらく、Microsoftがサポートしようとしているレベルよりも詳細なレベルです。これは、予告なく変更される可能性があることも意味します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.