stats_column_id e index_column_id non si aggiornano con l'ordine fisico dell'indice cluster modificato


14

A meno che non fraintenda lo scopo della colonna, il codice seguente indica che una modifica della struttura dell'indice cluster non modifica la posizione ordinale ( stats_column_id) della colonna nel DMV sys.stats_columns . (Testato in 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;

Tuttavia, i vettori di densità indicano una modifica nella colonna principale dell'oggetto indice / statistica. È un malinteso fondamentale da parte mia? In tal caso, come troverei la colonna principale di un oggetto statistico usando i DMV?

Versioni testate di SQL Server: 2008R2, 2014


1
Column_id non è la posizione ordinale nella tabella ? Cosa succede se si rilascia e si ricrea la tabella e si cambia effettivamente la posizione ordinale di quelle colonne? Non ho il tempo di testare adesso ma trovo sospettosamente conveniente che siano 1,2,3 nelle statistiche e 1,2,3 nella tabella e sys.columns.
Aaron Bertrand

@AaronBertrand yes. e quindi index_column_id è ... qualcosa ... ed key_ordinalè l'ordine delle colonne dell'indice (l' ho appena scoperto). tuttavia, la documentazione su sys.stats_columns sembra indicare che stats_column_id è la posizione ordinale, ma potrei leggere questo completamente sbagliato.
cambio il

2
immagino di poterlo usare INDEX_COL()anche se ricordo vagamente qualcuno che notava che quelle funzioni di supporto potrebbero non essere la migliore idea
swasheck

Risposte:


1

A detta di tutti, questo potrebbe essere un comportamento errato nel DMV sys.stats_columns. Ciò sembra causare problemi quando una statistica viene aggiornata tramite l'indice principale. Ritengo che ciò sia dovuto al meccanismo con cui le statistiche vengono aggiornate in una modifica del vincolo.

Se si crea manualmente una statistica e si desidera modificare le colonne, è necessario innanzitutto rilasciare e ricreare il che impone l'aggiornamento dei metadati nel DMV in questione. Nell'operazione che hai dimostrato sembra esserci una situazione in cui i metadati non vengono aggiornati in nessuna circostanza (DBCC *, CHECKPOINT, riavvio del server, aggiornamento delle statistiche tramite modifica dell'indice principale, ecc.) Una volta effettuata la modifica. Dal mio test iniziale posso trovare solo un caso in cui i metadati sono correttamente aggiornati, ovvero lo scenario di rilascio e ricrea.

Puoi dare un'occhiata alla voce Connetti sulla questione e votare in alto come appropriato. Esiste una soluzione intorno alla query pubblicata lì, ma il suo meccanismo si basa sulla corrispondenza del nome dell'indice con il nome della statistica e sull'utilizzo dei metadati dell'indice.


1

Stavo riscontrando lo stesso problema durante il tentativo di riprodurre il modo in cui altri recuperano le informazioni sull'indice dalle viste sys.dm in SQL Server. Non riuscivo a capire l'ordine delle colonne nell'indice.

Di seguito è riportato uno script creato per determinare l'ordine delle colonne in un determinato indice per una determinata tabella:

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 colonna key_ordinalnella tabella sys.index_columns è l'ordine in cui le colonne sono memorizzate nell'indice.

Non esiste una key_ordinalcolonna per la sys.stats_columnstabella. La colonna stats_column_idreplica semplicemente la index_column_idcolonna dell'oggetto a cui fa riferimento.

Esiste una leggera differenza nella formulazione dell'articolo sys.stats_columns (Transact-SQL) per la colonna stats_column_id:

Ordale basato su 1 all'interno di una serie di colonne delle statistiche.

... e nell'articolo sys.index_columns (Transact-SQL) per la key_ordinalcolonna:

Ordinale (basato su 1) all'interno di una serie di colonne- chiave .

Suppongo che la index_column_id(sys.index_columns) e stats_column_id(sys.stats_columns) siano equivalenti tra loro e che solo la tabella sys.index_columns abbia una colonna di ordinamento, vale a dire key_ordinal.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.