stats_column_id和index_column_id不会随着聚集索引的物理顺序更改而更新


14

除非我对列的用途有误解,否则以下代码指示更改聚集索引的结构不会更改sys.stats_columns DMV中stats_column_id列的顺序位置()。(在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;

但是,密度矢量指示索引/统计对象的前列发生了变化。这是我的基本误会吗?如果是这样,我如何使用DMV查找统计对象的开头?

经过测试的SQL Server版本:2008R2、2014


1
是不是COLUMN_ID顺序位置的表?如果删除并重新创建表并实际更改这些列的顺序位置会发生什么?我现在没有时间进行测试,但是我发现方便的是,它们在统计数据中分别为1,2,3,在表和sys.columns中分别为1,2,3。
亚伦·伯特兰

@AaronBertrand是的。然后index_column_id是...某物...并且key_ordinal是索引列的顺序(刚刚发现)。但是,有关sys.stats_columns的文档似乎表明stats_column_id是序数位置,但是我可能会完全错误地理解这一点。
swasheck

2
我想INDEX_COL()虽然可以隐约记得有人指出那些辅助功能可能不是最好的主意,但我还是可以使用
swasheck 2015年

Answers:


1

通过所有帐户,这可能是sys.stats_columns DMV中的错误行为。通过父索引更新统计信息时,这似乎引起了问题。我认为这是由于在约束更改中更新统计信息的机制所致。

如果您手动创建统计信息,然后希望更改列,则必须首先删除并重新创建,这将强制在相关DMV中更新元数据。在您演示的操作中,一旦发生更改,似乎在任何情况下都不会更新元数据(DBCC *,CHECKPOINT,服务器重启,通过父索引更改来更新统计信息等)。从最初的测试中,我发现只有一种情况可以正确地更新元数据,这就是删除并重新创建的场景。

您可以查看有关此问题的“ 连接”项目,并根据需要进行投票。有一种解决方法,其中发布了查询,但是其机制基于将索引名与统计信息名称匹配并利用索引元数据。


1

我在尝试重现其他人从SQL Server的sys.dm视图检索索引信息的方式时遇到了相同的问题。我只是无法弄清楚索引中列的顺序。

以下是我创建的脚本,用于确定给定表的任何给定索引中的列顺序:

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

key_ordinal在表sys.index_columns是其中列被存储在索引中的顺序。

key_ordinalsys.stats_columns表没有一列。该列stats_column_id只是复制index_column_id它引用的对象的列。

有一个在文章的措辞略有不同sys.stats_columns(的Transact-SQL)的列stats_column_id

一组统计信息列中基于1的序数。

...以及该列的sys.index_columns(Transact-SQL)文章中key_ordinal

列集中的序数(从1开始)。

我认为index_column_id(sys.index_columns)和stats_column_id(sys.stats_columns)彼此等效,并且只有sys.index_columns表具有排序列,即key_ordinal

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.