为什么在此列上自动创建的统计信息为空?


8

信息

我的问题与堆有关的中等大表(〜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])

在此处输入图片说明

Answers:


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

输出量

我发现对所有非空重复项的修改都可以继续被准确跟踪,但是只有一个统计信息会自动更新(无论异步设置如何)。

自动统计信息更新仅在查询优化器需要特定统计信息并发现其过时时才会发生(与优化有关的重新编译)。

SQL Server 2012中的计划缓存和重新编译中所述,优化器从重复的统计信息中进行选择:

与本文档的主题不直接相关的问题是:在相同顺序的同一列集合上具有多个统计信息,查询优化器如何确定在查询优化期间要加载哪些统计信息?答案并不简单,但是查询优化器使用以下准则:优先考虑使用FULLSCAN选项计算的统计数据而不是使用采样计算的统计数据;等等。

问题的关键是优化程序选择一个可用的重复统计(“最好的一个),如果发现是陈旧的,一个是自动更新。

我认为这是旧版本中行为的变化-至少文档说明该对象的所有过时统计信息都将作为此过程的一部分进行更新,但是我不知道何时更改。肯定是在2013年8月之后,Matt Bowler发布了Duplicate Statistics,其中包含一个方便的基于AdventureWorks的存储库。该脚本现在仅导致更新一个统计对象,而当时两个都被更新。

上面的解释与我尝试重现您的方案时观察到的所有行为均相符,但我怀疑它在任何地方都已明确记录。看起来确实是明智的优化,因为保持完全更新重复项几乎没有价值。

这可能只是微软愿意支持的细节而已。这也意味着它可能会更改,恕不另行通知。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.