stats_column_id et index_column_id ne sont pas mis à jour avec l'ordre physique de l'index clusterisé est modifié

14

À moins que je ne comprenne mal le but de la colonne, le code suivant indique qu'un changement de la structure de l'index cluster ne change pas la position ordinale ( stats_column_id) de la colonne dans le DMV sys.stats_columns . (Testé dans AdventureWorks2014, AdventureWorks2008R2)

select i.name, c.name, ic.column_id, ic.index_column_id
from sys.indexes i 
join sys.index_columns ic
    on i.object_id = ic.object_id
    and i.index_id = ic.index_id
join sys.columns c 
    on i.object_id = c.object_id
    and ic.column_id = c.column_id
where i.name = 'PK_BusinessEntityAddress_BusinessEntityID_AddressID_AddressTypeID'
order by ic.key_ordinal;

select sh.name,s.name, c.name, c.column_id, sc.column_id, sc.stats_column_id
from sys.stats s 
join sys.stats_columns sc
    on s.object_id = sc.object_id
    and s.stats_id = sc.stats_id
join sys.columns c 
    on s.object_id = c.object_id
    and sc.column_id = c.column_id
join sys.tables t 
    on s.object_id = t.object_id
join sys.schemas sh
    on t.schema_id = sh.schema_id
where s.name = 'PK_BusinessEntityAddress_BusinessEntityID_AddressID_AddressTypeID'
order by sc.stats_column_id;

dbcc show_statistics('[Person].[BusinessEntityAddress]','PK_BusinessEntityAddress_BusinessEntityID_AddressID_AddressTypeID') with density_vector;

ALTER TABLE [Person].[BusinessEntityAddress] DROP CONSTRAINT [PK_BusinessEntityAddress_BusinessEntityID_AddressID_AddressTypeID]
GO

ALTER TABLE [Person].[BusinessEntityAddress] ADD  CONSTRAINT [PK_BusinessEntityAddress_BusinessEntityID_AddressID_AddressTypeID] PRIMARY KEY CLUSTERED 
(
    AddressID ASC,
    [BusinessEntityID] ASC, 
    [AddressTypeID] ASC
)
GO


select i.name, c.name, ic.column_id, ic.index_column_id
from sys.indexes i 
join sys.index_columns ic
    on i.object_id = ic.object_id
    and i.index_id = ic.index_id
join sys.columns c 
    on i.object_id = c.object_id
    and ic.column_id = c.column_id
where i.name = 'PK_BusinessEntityAddress_BusinessEntityID_AddressID_AddressTypeID'
order by ic.key_ordinal;

select sh.name,s.name, c.name, c.column_id, sc.column_id, sc.stats_column_id
from sys.stats s 
join sys.stats_columns sc
    on s.object_id = sc.object_id
    and s.stats_id = sc.stats_id
join sys.columns c 
    on s.object_id = c.object_id
    and sc.column_id = c.column_id
join sys.tables t 
    on s.object_id = t.object_id
join sys.schemas sh
    on t.schema_id = sh.schema_id
where s.name = 'PK_BusinessEntityAddress_BusinessEntityID_AddressID_AddressTypeID'
order by sc.stats_column_id;

dbcc show_statistics('[Person].[BusinessEntityAddress]','PK_BusinessEntityAddress_BusinessEntityID_AddressID_AddressTypeID') with density_vector;

Cependant, les vecteurs de densité indiquent un changement dans la colonne de tête de l'objet index / statistiques. Est-ce un malentendu fondamental de ma part? Si oui, comment trouver la première colonne d'un objet de statistiques à l'aide de DMV?

Versions testées de SQL Server: 2008R2, 2014

swasheck
la source
1
Le column_id n'est-il pas la position ordinale dans la table ? Que se passe-t-il si vous supprimez et recréez la table et modifiez réellement la position ordinale de ces colonnes? Je n'ai pas le temps de tester pour le moment mais je trouve étrangement pratique que ce soit 1,2,3 dans les statistiques et 1,2,3 dans le tableau et sys.columns.
Aaron Bertrand
@AaronBertrand oui. puis index_column_id est ... quelque chose ... et key_ordinalest l'ordre des colonnes d'index (je viens de le découvrir). cependant, la documentation sur sys.stats_columns semble indiquer que stats_column_id est la position ordinale, mais je pourrais lire ceci complètement faux.
swasheck
2
je suppose que je pourrais simplement l'utiliser INDEX_COL()même si je me souviens vaguement que quelqu'un a noté que ces fonctions d'aide n'étaient peut-être pas la meilleure idée
swasheck

Réponses:

1

Par tous les comptes, cela peut être un comportement bogue dans le DMV sys.stats_columns. Cela semble poser des problèmes lorsqu'une statistique est mise à jour via l'index parent. Je pense que cela est dû au mécanisme avec lequel les statistiques sont mises à jour lors d'un changement de contrainte.

Si vous créez une statistique manuellement et souhaitez ensuite modifier les colonnes, vous devez d'abord supprimer et recréer, ce qui force les métadonnées à être mises à jour dans le DMV en question. Dans l'opération que vous avez démontrée, il semble y avoir une situation dans laquelle les métadonnées ne sont en aucun cas mises à jour (DBCC *, CHECKPOINT, redémarrage du serveur, mise à jour des statistiques via la modification de l'index parent, etc.) une fois la modification effectuée. D'après mes tests initiaux, je ne peux trouver qu'un seul cas où les métadonnées sont correctement mises à jour, c'est le scénario de suppression et de recréation.

Vous pouvez jeter un œil à l' élément Connect sur la question et voter de manière appropriée. Il y a un travail autour de la requête qui y est publiée mais son mécanisme est basé sur la correspondance du nom d'index avec le nom de statistique et en utilisant les métadonnées d'index.

Page Travis
la source
1

J'avais le même problème en essayant de reproduire la façon dont les autres récupèrent les informations d'index à partir des vues sys.dm dans SQL Server. Je ne pouvais tout simplement pas comprendre l'ordre des colonnes dans l'index.

Voici un script que j'ai créé pour déterminer l'ordre des colonnes dans un index donné pour une table donnée:

SELECT s.name                  AS Schema_name,
       o.name                  AS Table_Name,
       i.type_desc             AS Index_Type,
       i.name                  AS Index_Name,
       c.name           AS Table_Column,
       i.fill_factor           AS Indx_Fill_Factor,
       ic.key_ordinal          AS [Key_ordinal (IDX Column_Order)],
       ic.index_column_id      AS Index_column_id,
       stc.stats_column_id     AS Stats_Col_ID,
       -- Additional info for each joined table
       -- comment out what you don't need
       -- 2 lines at a time
       --
       -- '| table object -->', -- column seperator
       -- o.*,
       -- '| schema object-->', -- column seperator
       -- s.*,
       '| index info-->', -- column seperator
       i.*,
       '| sys index info -->', -- column seperator
       si.*,
       '| indx cols info -->', -- column seperator
       ic.*,
       '| tab cols info -->', -- column seperator
       c.*,
       '| idx stats info -->', -- column seperator
       st.*,
       '| idx stats columns info -->', -- column seperator
       stc.*
FROM   sys.objects             AS o
       JOIN sys.schemas        AS s
            ON  s.schema_id = o.schema_id
       JOIN sys.indexes        AS i
            ON  i.object_id = o.object_id
       JOIN sys.sysindexes as si
            ON  si.[id] = i.object_id
            AND si.indid = i.index_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  c.object_id = ic.object_id
            AND c.column_id = ic.column_id
       JOIN sys.stats          AS st
            ON  st.object_id = i.object_id
            and st.stats_id = i.index_id 
      JOIN sys.stats_columns  AS stc
      ON c.column_id = stc.column_id
      AND stc.stats_id = st.stats_id
      AND stc.[object_id] = o.[object_id]
WHERE  1=1 
     --and i.type <> 1 -- Exclude Clustered Indexes. 0 = Heap; 1 = Clustered Index, 2 = Non-Clustered Index
       AND s.name != 'sys' -- Exclude sys items
       and o.name = 'BusinessEntityAddress'
       AND i.name = 'PK_BusinessEntityAddress_BusinessEntityID_AddressID_AddressTypeID'
ORDER BY
       o.object_id,
       i.index_id,
       ic.key_ordinal

La colonne key_ordinalde la table sys.index_columns est l'ordre dans lequel les colonnes sont stockées dans l'index.

Il n'y a pas de key_ordinalcolonne pour le sys.stats_columnstableau. La colonne stats_column_idréplique simplement la index_column_idcolonne de l'objet auquel elle fait référence.

Il y a une légère différence dans le libellé de l'article sys.stats_columns (Transact-SQL) pour la colonne stats_column_id:

Ordinal basé sur 1 dans un ensemble de colonnes de statistiques.

... et dans l'article sys.index_columns (Transact-SQL) pour la key_ordinalcolonne:

Ordinal (basé sur 1) dans un ensemble de colonnes clés .

Je pense que index_column_id(sys.index_columns) et stats_column_id(sys.stats_columns) sont équivalents l'un de l'autre et que seule la table sys.index_columns a une colonne de commande, à savoir key_ordinal.

John aka hot2use
la source