stats_column_id e index_column_id no se actualizan con el orden físico del índice agrupado se cambia

14

A menos que no entienda el propósito de la columna, el siguiente código indica que un cambio en la estructura del índice agrupado no cambia la posición ordinal ( stats_column_id) de la columna en el DMV sys.stats_columns . (Probado en 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;

Sin embargo, los vectores de densidad indican un cambio en la columna inicial del objeto de índice / estadística. ¿Es este un malentendido fundamental de mi parte? Si es así, ¿cómo encontraría la columna inicial de un objeto de estadísticas usando DMV?

Versiones de SQL Server probadas: 2008R2, 2014

swasheck
fuente
1
¿No es column_id la posición ordinal en la tabla ? ¿Qué sucede si sueltas y vuelves a crear la tabla y realmente cambias la posición ordinal de esas columnas? No tengo tiempo para probar en este momento, pero me parece sospechosamente conveniente que sean 1,2,3 en las estadísticas y 1,2,3 en la tabla y las columnas del sistema.
Aaron Bertrand
@AaronBertrand sí. y luego index_column_id es ... algo ... y key_ordinales el orden de las columnas de índice (acabo de descubrir eso). sin embargo, la documentación en sys.stats_columns parece indicar que stats_column_id es la posición ordinal, pero podría estar leyendo esto completamente mal.
swasheck
2
Creo que sólo podía usar INDEX_COL()aunque recuerdo vagamente a alguien señalando que esas funciones de ayuda pueden no ser la mejor idea
swasheck

Respuestas:

1

Según todas las cuentas, esto puede ser un comportamiento con errores en el DMV sys.stats_columns. Esto parece estar causando problemas cuando se actualiza una estadística por medio del índice padre. Creo que esto se debe al mecanismo con el que las estadísticas se actualizan en un cambio de restricción.

Si crea una estadística manualmente y luego desea cambiar las columnas, primero debe soltar y volver a crear, lo que obliga a actualizar los metadatos en el DMV en cuestión. En la operación que ha demostrado, parece haber una situación en la que los metadatos no se actualizan bajo ninguna circunstancia (DBCC *, CHECKPOINT, reinicio del servidor, actualización de estadísticas a través del cambio de índice principal, etc.) una vez que se ha realizado el cambio. Desde mi prueba inicial, solo puedo encontrar un caso cuando los metadatos se actualizan correctamente, que es el escenario de caída y recreación.

Puede echar un vistazo al elemento de Connect sobre el tema y votar arriba según corresponda. Allí se publica una consulta alternativa, pero su mecanismo se basa en hacer coincidir el nombre del índice con el nombre de la estadística y utilizar los metadatos del índice.

Página de Travis
fuente
1

Estaba teniendo el mismo problema al intentar reproducir la forma en que otros recuperan la información del índice de las vistas sys.dm en SQL Server. Simplemente no podía entender el orden de las columnas en el índice.

El siguiente es un script que creé para determinar el orden de las columnas en cualquier índice dado para una tabla dada:

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 columna key_ordinalen la tabla sys.index_columns es el orden en que las columnas se almacenan en el índice.

No hay una key_ordinalcolumna para la sys.stats_columnstabla. La columna stats_column_idsimplemente replica la index_column_idcolumna del objeto al que hace referencia.

Hay una ligera diferencia en la redacción del artículo sys.stats_columns (Transact-SQL) para la columna stats_column_id:

Ordinal basado en 1 dentro del conjunto de columnas de estadísticas.

... y en el artículo sys.index_columns (Transact-SQL) para la key_ordinalcolumna:

Ordinal (basado en 1) dentro del conjunto de columnas clave .

Creo que el index_column_id (sys.index_columns) y stats_column_id(sys.stats_columns) son equivalentes entre sí y que solo la tabla sys.index_columns tiene una columna de ordenamiento, a saber key_ordinal.

John aka hot2use
fuente