stats_column_id e index_column_id não atualizam com a ordem física do índice clusterizado é alterado

14

A menos que eu esteja entendendo mal a finalidade da coluna, o código a seguir indica que uma alteração na estrutura do índice em cluster não altera a posição ordinal ( stats_column_id) da coluna na DMV sys.stats_columns . (Testado no 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;

No entanto, os vetores de densidade indicam uma alteração na coluna inicial do objeto de índice / estatística. Isso é um mal-entendido fundamental da minha parte? Se sim, como eu encontraria a coluna principal de um objeto de estatística usando DMVs?

Versões testadas do SQL Server: 2008R2, 2014

swasheck
fonte
1
A column_id não é a posição ordinal na tabela ? O que acontece se você soltar e recriar a tabela e realmente alterar a posição ordinal dessas colunas? Não tenho tempo para testar agora, mas acho suspeito que seja 1,2,3 nas estatísticas e 1,2,3 na tabela e sys.columns.
Aaron Bertrand
@AaronBertrand yes. e index_column_id é ... alguma coisa ... e key_ordinalé a ordem das colunas de índice (acabei de descobrir isso). no entanto, a documentação em sys.stats_columns parece indicar que stats_column_id é a posição ordinal, mas eu poderia estar lendo isso completamente errado.
swasheck 04/02
2
eu acho que eu poderia usar apenas INDEX_COL()embora Lembro-me vagamente de alguém observando que essas funções auxiliares podem não ser a melhor idéia
swasheck

Respostas:

1

Por todas as contas, esse pode ser um comportamento com erros na DMV sys.stats_columns. Parece estar causando problemas quando uma estatística é atualizada por meio do índice pai. Eu acredito que isso se deve ao mecanismo com o qual as estatísticas estão sendo atualizadas em uma alteração de restrição.

Se você criar uma estatística manualmente e depois desejar alterar as colunas, você deve primeiro eliminar e recriar o que força os metadados a serem atualizados na DMV em questão. Na operação que você demonstrou, parece haver uma situação em que os metadados não são atualizados sob nenhuma circunstância (DBCC *, CHECKPOINT, reinicialização do servidor, atualização de estatísticas por meio da alteração do índice pai, etc.) depois que a alteração é feita. No meu teste inicial, posso encontrar apenas um caso em que os metadados são atualizados corretamente, que é o cenário de descartar e recriar.

Você pode dar uma olhada no item do Connect sobre o problema e votar novamente, conforme apropriado. Existe uma solução alternativa para a consulta publicada lá, mas seu mecanismo é baseado na correspondência do nome do índice com o nome da estatística e na utilização dos metadados do índice.

Travis Page
fonte
1

Eu estava tendo o mesmo problema ao tentar reproduzir a maneira como outras pessoas recuperam informações de índice dos modos de exibição sys.dm no SQL Server. Eu simplesmente não conseguia descobrir a ordem das colunas no índice.

A seguir, um script que criei para determinar a ordem das colunas em qualquer índice para uma determinada tabela:

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

A coluna key_ordinalna tabela sys.index_columns é a ordem em que as colunas são armazenadas no índice.

Não há uma key_ordinalcoluna para a sys.stats_columnstabela. A coluna stats_column_idapenas replica a index_column_idcoluna do objeto que faz referência.

Há uma pequena diferença na redação do artigo sys.stats_columns (Transact-SQL) para a coluna stats_column_id:

Ordinal baseado em 1 no conjunto de colunas de estatísticas.

... e no artigo sys.index_columns (Transact-SQL) da key_ordinalcoluna:

Ordinal (com base em 1) no conjunto de colunas- chave .

Eu acho que as index_column_id(sys.index_columns) e stats_column_id(sys.stats_columns) são equivalentes entre si e que apenas a tabela sys.index_columns possui uma coluna de pedidos, a saber key_ordinal.

John aka hot2use
fonte