Sys.stats_columns está incorreto?

28

Digamos que eu tenha uma tabela Foocom colunas ID1, ID2e uma chave primária composta definida sobre ID2, ID1. (No momento, estou trabalhando com um produto System Center que possui várias tabelas definidas dessa maneira com as colunas da chave primária listadas na ordem oposta em que aparecem na definição da tabela.)

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;

A key_ordinalcoluna em sys.index_columnsmostra as colunas de índice na mesma ordem em que foram declaradas na chave primária composta:

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

índice

O histograma também mostra as estatísticas na mesma ordem:

DBCC SHOW_STATISTICS ('Foo',PK_Foo);

Estatísticas

No entanto, sys.stats_columnsmostra as colunas listadas na ordem inversa ( 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';

estatísticas_colunas

O Books Online diz que stats_column_idé um "ordinal baseado em 1 no conjunto de colunas de estatísticas", então eu esperava que o valor 1 aponte para a primeira coluna no objeto de estatísticas.

Isso é um bug sys.stats_columnsou um mal-entendido da minha parte?

Verifiquei que esse comportamento ocorre nas versões atuais do SQL Server 2005, 2008, 2008 R2, 2012 e 2014.

sys.stats_columns parece refletir a ordem no objeto de estatísticas em outras situações, por exemplo:

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

morestats

Aqui está outro exemplo em que sys.stats_columnsparece retornar os dados corretos, desta vez para estatísticas em um índice:

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

moremorestats

James L
fonte
3
Eu tive a mesma pergunta há alguns meses, mas a excluí. Me desculpe por isso. No entanto, o stats_column_idin sys.stats_columnsparece não fazer o que diz que faz. Como você está apoiando um índice, eu continuaria com a ordem da coluna do índice. Se você está apenas olhando para as estatísticas objetos parece que index_col()é a melhor opção atualmente
swasheck
5
Talvez você deva / possa registrar um item do Microsoft Connect para isso? Parece buggy para mim.
Max Vernon
6
@MaxVernon, swashesk registrou um aqui
James L

Respostas:

5

Este parece ser um erro antigo:

swasheck - 5 de março de 2015 postou:

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

O MSDN observa que sys.stats_columns.stats_column_id é "ordinal baseado em 1 no conjunto de colunas de estatísticas". No entanto, parece realmente refletir a ordem de definição da tabela. A alteração da ordem do índice não é refletida em sys.stats_columns.

Max Vernon e James Lupolt parecem concordar com base em seus comentários / incentivos.

RLF
fonte