Sql-Server

為什麼此列上自動創建的統計資訊為空?

  • February 1, 2019

資訊

我的問題與一個中等大小的表(約 40GB 數據空間)有關,它是一個堆

(不幸的是,應用程序所有者不允許我向表中添加聚集索引)

已創建身份列 ( ) 上的自動創建統計資訊ID,但為空。

  • 自動創建統計資訊和自動更新統計資訊已開啟
  • 表中發生了修改
  • 還有其他(自動創建的)統計資訊正在更新
  • 索引創建的同一列上還有另一個統計資訊(重複)
  • 建構:12.0.5546

重複統計資訊正在更新: 在此處輸入圖像描述

實際問題

據我了解,即使在完全相同的列(重複)上有兩個統計資訊,也可以使用所有統計資訊並跟踪修改,那麼為什麼這個統計資訊仍然為空?

統計資訊

在此處輸入圖像描述

數據庫統計資訊

在此處輸入圖像描述

表大小

在此處輸入圖像描述

創建統計資訊的列資訊

在此處輸入圖像描述

[ID] [int] IDENTITY(1,1) NOT NULL

身份欄

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');

輸出

我發現在所有非空副本上繼續準確跟踪修改,但只有一個統計資訊自動更新(無論非同步設置如何)。

僅當查詢優化器需要特定統計資訊並發現它已過時(與最優性相關的重新編譯)時,才會自動更新統計資訊。

優化器從SQL Server 2012中的計劃記憶體和重新編譯論文中提到的重複統計資訊中進行選擇:

與本文件主題沒有直接關係的一個問題是:給定同一組列的多個統計資訊以相同的順序,查詢優化器如何決定在查詢優化期間載入哪些統計資訊?答案並不簡單,但查詢優化器使用以下準則: 優先考慮最近的統計資訊而不是舊的統計資訊;優先考慮使用FULLSCAN選項計算的統計數據,而不是使用抽樣計算的統計數據;等等。

關鍵是優化器選擇了一種可用的重複統計資訊(“最佳統計資訊”),如果發現它是陳舊的,它會自動更新。

我相信這是舊版本的行為變化 - 或者至少文件表明對象的所有過時統計資訊都將作為此過程的一部分進行更新,但我不知道何時發生變化。肯定是在 2013 年 8 月之後,Matt Bowler 發布了Duplicate Statistics,其中包含一個方便的基於 AdventureWorks 的 repo。該腳本現在只更新了一個統計對象,而當時兩者都更新了。

上述解釋與我在嘗試重現您的場景時觀察到的所有行為相匹配,但我懷疑它是否在任何地方都明確記錄。這似乎是一個明智的優化,因為保持副本完全更新幾乎沒有價值。

這可能都比微軟願意支持的詳細程度低。這也意味著它可能會更改,恕不另行通知。

引用自:https://dba.stackexchange.com/questions/228656