sql-server – sys.stats_columns不正确吗?

假设我有一个表Foo,其列ID1,ID2和在ID2,ID1上定义的复合主键. (我目前正在使用System Center产品,该产品具有以这种方式定义的多个表,主键列按照它们在表定义中出现的相反顺序列出.)
CREATE TABLE dbo.Foo(
  ID1 int NOT NULL,ID2 int NOT NULL,CONSTRAINT [PK_Foo] PRIMARY KEY CLUSTERED (ID2,ID1)
);
GO

-- Add a row and update stats so that histogram isn't empty
INSERT INTO Foo (ID1,ID2) VALUES (1,2);
UPDATE STATISTICS dbo.Foo;

sys.index_columns中的key_ordinal列以与复合主键中声明的顺序相同的顺序显示索引列:

SELECT t.name,i.name,c.column_id,c.name,ic.index_column_id,ic.key_ordinal
FROM sys.tables AS t
JOIN sys.indexes AS i
ON t.[object_id] = i.[object_id]
JOIN sys.index_columns AS ic
ON ic.[object_id] = i.[object_id]
AND ic.index_id = i.index_id
JOIN sys.columns AS c
ON ic.column_id = c.column_id
AND ic.[object_id] = c.[object_id]
WHERE t.name = 'Foo';

直方图还以相同的顺序显示统计信息:

DBCC SHOW_STATISTICS ('Foo',PK_Foo);

但是,sys.stats_columns显示以反向顺序列出的列(ID1,ID2).

SELECT s.name,sc.stats_column_id,c.name
FROM sys.stats AS s
JOIN sys.stats_columns AS sc 
ON s.stats_id = sc.stats_id 
AND s.[object_id] = sc.[object_id] 
JOIN sys.columns AS c 
ON c.[object_id] = s.[object_id]
AND c.column_id = sc.column_id
JOIN sys.objects AS o 
ON o.[object_id] = c.[object_id] 
WHERE o.name = 'Foo'
AND s.name = 'PK_Foo';

Books Online表示stats_column_id是“stats列集中的基于1的序数”,因此我期望值1指向统计对象中的第一列.

这是sys.stats_columns中的错误还是我的误解?

我已经验证了此行为发生在sql Server 2005,2008,2008 R2,2012和2014的当前版本上.

sys.stats_columns似乎反映了统计对象在其他情况下的顺序,例如:

CREATE TABLE dbo.Foo2(
  ID1 int NOT NULL,ID3 int NULL,String VARCHAR(10) NULL,CONSTRAINT [PK_Foo2] PRIMARY KEY CLUSTERED (ID2,ID1)
);

GO

INSERT INTO Foo2 (ID1,ID2,ID3,String) VALUES (1,2,3,'String');

CREATE STATISTICS ST_Test ON Foo2 (ID3,String);
CREATE STATISTICS ST_Test2 ON Foo2 (String,ID3);

DBCC SHOW_STATISTICS ('Foo2',ST_Test);
DBCC SHOW_STATISTICS ('Foo2',ST_Test2);


SELECT s.name,c.name
FROM sys.stats AS s
JOIN sys.stats_columns AS sc 
ON s.stats_id = sc.stats_id 
AND s.[object_id] = sc.[object_id] 
JOIN sys.columns AS c 
ON c.[object_id] = s.[object_id]
AND c.column_id = sc.column_id
JOIN sys.objects AS o 
ON o.[object_id] = c.[object_id] 
WHERE o.name = 'Foo2'
AND s.name LIKE 'ST_Test%';

这是另一个示例,其中sys.stats_columns似乎返回正确的数据,这次是对索引的统计信息:

--drop table dbo.Foo3
CREATE TABLE dbo.Foo3(
  ID1 int NOT NULL,CONSTRAINT [PK_Foo3] PRIMARY KEY CLUSTERED (ID2,ID1)
);

GO

INSERT INTO Foo3 (ID1,'String');
UPDATE STATISTICS Foo3;

CREATE INDEX IX_Test ON Foo3 (ID3,String);
CREATE INDEX IX_Test2 ON Foo3 (String,ID3);

DBCC SHOW_STATISTICS ('Foo3',IX_Test);
DBCC SHOW_STATISTICS ('Foo3',IX_Test2);

SELECT s.name,c.name
FROM sys.stats AS s
JOIN sys.stats_columns AS sc 
ON s.stats_id = sc.stats_id 
AND s.[object_id] = sc.[object_id] 
JOIN sys.columns AS c 
ON c.[object_id] = s.[object_id]
AND c.column_id = sc.column_id
JOIN sys.objects AS o 
ON o.[object_id] = c.[object_id] 
WHERE o.name = 'Foo3'
AND s.name LIKE 'IX_Test%';

解决方法

这似乎是一个长期存在的错误

swasheck – 2015年3月5日发布:

https://connect.microsoft.com/SQLServer/feedback/details/1163126

MSDN notes that sys.stats_columns.stats_column_id is “1-based ordinal
within set of stats columns.” However,it seems to actually reflect
table deFinition order. Altering index order is not reflected in
sys.stats_columns.

Max Vernon和James Lupolt似乎同意他们的评论/鼓励.

相关文章

SELECT a.*,b.dp_name,c.pa_name,fm_name=(CASE WHEN a.fm_n...
if not exists(select name from syscolumns where name=&am...
select a.*,pano=a.pa_no,b.pa_name,f.dp_name,e.fw_state_n...
要在 SQL Server 2019 中设置定时自动重启,可以使用 Window...
您收到的错误消息表明数据库 'EastRiver' 的...
首先我需要查询出需要使用SQL Server Profiler跟踪的数据库标...