¿Sys.stats_columns es incorrecto?

28

Digamos que tengo una tabla Foocon columnas ID1, ID2y una clave primaria compuesta definida ID2, ID1. (Actualmente estoy trabajando con un producto de System Center que tiene varias tablas definidas de esta manera con las columnas de clave principal enumeradas en el orden opuesto que aparecen en la definición de la tabla).

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;

La key_ordinalcolumna en sys.index_columnsmuestra las columnas de índice en el mismo orden en que se declararon en la clave primaria compuesta:

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

El histograma también muestra las estadísticas en el mismo orden:

DBCC SHOW_STATISTICS ('Foo',PK_Foo);

estadísticas

Sin embargo, sys.stats_columnsmuestra las columnas enumeradas en orden inverso ( 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';

stats_columns

Books Online dice que stats_column_ides un "ordinal basado en 1 dentro de un conjunto de columnas de estadísticas", por lo que esperaba que el valor 1 apuntara a la primera columna en el objeto de estadísticas.

¿Es esto un error sys.stats_columnso un malentendido de mi parte?

Verifiqué que este comportamiento se produce en las versiones actuales de SQL Server 2005, 2008, 2008 R2, 2012 y 2014.

sys.stats_columns parece reflejar el orden dentro del objeto de estadísticas en otras situaciones, por ejemplo:

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

Aquí hay otro ejemplo en el que sys.stats_columnsparece devolver los datos correctos, esta vez para estadísticas en un í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
fuente
3
Tuve la misma pregunta hace unos meses pero la eliminé. Lo siento por eso. Sin embargo, el stats_column_iden sys.stats_columnsparece no hacer lo que dice que hace. Debido a que está respaldando un índice, me quedaría con el orden de las columnas del índice. Si solo está mirando objetos de estadísticas, parece que index_col()es la mejor opción actualmente
swasheck el
55
¿Quizás debería / podría presentar un elemento de Microsoft Connect para esto? Me parece con errores.
Max Vernon
66
@MaxVernon, swashesk ha presentado uno aquí
James L

Respuestas:

5

Esto parece ser un error de larga data:

swasheck - 5 de marzo de 2015 publicado:

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

MSDN señala que sys.stats_columns.stats_column_id es "ordinal basado en 1 dentro del conjunto de columnas de estadísticas". Sin embargo, parece reflejar el orden de definición de la tabla. La alteración del orden del índice no se refleja en sys.stats_columns.

Max Vernon y James Lupolt parecen estar de acuerdo con base en sus comentarios / estímulo.

RLF
fuente