假设我有一个Foo包含列的表ID1, ID2和一个复合主键定义在ID2, ID1. (我目前正在使用一个 System Center 产品,该产品具有以这种方式定义的多个表,主键列以它们在表定义中出现的相反顺序列出。)
Foo
ID1, ID2
ID2, ID1
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;
中的key_ordinal列以sys.index_columns与复合主键中声明的顺序相同的顺序显示索引列:
key_ordinal
sys.index_columns
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)。
sys.stats_columns
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是“一组统计列中基于 1 的序数”,所以我期望值 1 指向统计对象中的第一列。
stats_column_id
这是sys.stats_columns我的错误还是误解?
我已验证此行为发生在 SQL Server 2005、2008、2008 R2、2012 和 2014 的当前版本上。
sys.stats_columns似乎在其他情况下反映了统计对象内的顺序,例如:
CREATE TABLE dbo.Foo2( ID1 int NOT NULL, ID2 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, 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 = 'Foo2' AND s.name LIKE 'ST_Test%';
这是另一个sys.stats_columns似乎返回正确数据的示例,这次是针对索引的统计信息:
--drop table dbo.Foo3 CREATE TABLE dbo.Foo3( ID1 int NOT NULL, ID2 int NOT NULL, ID3 int NULL, String VARCHAR(10) NULL, CONSTRAINT [PK_Foo3] PRIMARY KEY CLUSTERED (ID2, ID1) ); GO INSERT INTO Foo3 (ID1, ID2, ID3, String) VALUES (1,2,3,'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, 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 = 'Foo3' AND s.name LIKE 'IX_Test%';
这似乎是一个长期存在的错误:
MSDN 指出 sys.stats_columns.stats_column_id 是“一组统计数据列中基于 1 的序数”。但是,它似乎实际上反映了表定义顺序。更改索引顺序不会反映在 sys.stats_columns 中。
Max Vernon 和 James Lupolt 似乎基于他们的评论/鼓励而同意。