Sys.stats_columns est-il incorrect?

28

Disons que j'ai une table Fooavec des colonnes ID1, ID2et une clé primaire composite définie sur ID2, ID1. (Je travaille actuellement avec un produit System Center qui a plusieurs tables définies de cette façon avec les colonnes de clé primaire répertoriées dans l'ordre inverse de leur apparition dans la définition de table.)

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_ordinalcolonne dans sys.index_columnsaffiche les colonnes d'index dans le même ordre qu'elles ont été déclarées dans la clé primaire composite:

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

indice

L'histogramme montre également les statistiques dans le même ordre:

DBCC SHOW_STATISTICS ('Foo',PK_Foo);

Statistiques

Cependant, sys.stats_columnsaffiche les colonnes répertoriées dans l'ordre inverse ( 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 indique qu'il stats_column_ids'agit d'un "ordinal basé sur 1 dans un ensemble de colonnes de statistiques", donc je m'attendais à ce que la valeur 1 pointe vers la première colonne de l'objet de statistiques.

Est-ce un bug sys.stats_columnsou un malentendu de ma part?

J'ai vérifié que ce problème se produit sur les versions actuelles de SQL Server 2005, 2008, 2008 R2, 2012 et 2014.

sys.stats_columns semble refléter l'ordre dans l'objet statistique dans d'autres situations, par exemple:

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

Voici un autre exemple où sys.stats_columnssemble renvoyer les données correctes, cette fois pour les statistiques sur un index:

--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
la source
3
J'avais la même question il y a quelques mois mais je l'ai supprimée. Désolé pour ça. Néanmoins, l' stats_column_idin sys.stats_columnsne semble pas faire ce qu'il dit. Parce que vous sauvegardez un index, je m'en tiendrai à l'ordre des colonnes d'index. Si vous regardez simplement les objets statistiques, il semble que index_col()c'est la meilleure option actuellement
swasheck
5
Peut-être devriez-vous / pourriez-vous déposer un élément Microsoft Connect pour cela? Semble buggy pour moi.
Max Vernon
6
@MaxVernon, swashesk en a déposé un ici
James L

Réponses:

5

Cela semble être une erreur de longue date:

swasheck - 5 mars 2015 publié:

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

MSDN note que sys.stats_columns.stats_column_id est "ordinal basé sur 1 dans un ensemble de colonnes de statistiques". Cependant, il semble réellement refléter l'ordre de définition des tables. La modification de l'ordre des index n'est pas reflétée dans sys.stats_columns.

Max Vernon et James Lupolt semblent être d'accord sur la base de leurs commentaires / encouragements.

RLF
la source