Columnstore index analysis does not point me to correct columns

All we need is an easy explanation of the problem, so here it is.

I am using this query to look deeper onto my columnstore indexes while t-shooting my execution plans (i.e. segment elimination etc.) :

    SELECT AS table_name, AS index_name, AS column_name,
FROM sys.column_store_segments
INNER JOIN sys.partitions
ON column_store_segments.hobt_id = partitions.hobt_id
INNER JOIN sys.indexes
ON indexes.index_id = partitions.index_id
AND indexes.object_id = partitions.object_id
INNER JOIN sys.tables
ON tables.object_id = indexes.object_id
INNER JOIN sys.columns
ON tables.object_id = columns.object_id
AND column_store_segments.column_id = 
WHERE = 'R***'


(table name redacted).

The result of the analysis is as follows:

My question is simple: How come in the outcome of the analysis does not correspond to the columns name in the indexes? As you can see on the right part of the image, the column names on the result grid are different to what is shown in columnstore index properties.

Environment: SQL 2019 CU10 Standard ; Windows Server 2019.

Thank you in advance for a feedback,
take care S.

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

The column_id field that is part of the columnstore system catalog view: sys.column_store_segments

column_id int ID of the columnstore column.


Is different from the column_id field that is part of the system catalog view: sys.columns

column_id int ID of the column. Is unique within the object.


If you are ever wondered about what SSMS is running in the background you can always set up an extended event to capture the queries when you select the properties of the index.
The query that SSMS uses that shows the properties of the index and the columns in correct order:

exec sp_executesql N'SELECT
(case ic.key_ordinal when 0 then ic.index_column_id else ic.key_ordinal end) AS [ID], AS [Name],
ic.is_included_column AS [IsIncluded],
ic.is_descending_key AS [Descending],
CAST(COLUMNPROPERTY(ic.object_id,, N''IsComputed'') AS bit) AS [IsComputed],
CAST(ISNULL(ic.column_store_order_ordinal,0) AS int) AS [ColumnStoreOrderOrdinal]
sys.tables AS tbl
INNER JOIN sys.indexes AS i ON (i.index_id > @_msparam_0 and i.is_hypothetical = @_msparam_1) AND (i.object_id=tbl.object_id)
INNER JOIN sys.index_columns AS ic ON (ic.column_id > 0 and (ic.key_ordinal > 0 or ic.partition_ordinal = 0 or ic.is_included_column != 0)) AND (ic.index_id=CAST(i.index_id AS int) AND ic.object_id=i.object_id)
INNER JOIN sys.columns AS clmns ON clmns.object_id = ic.object_id and clmns.column_id = ic.column_id
([email protected]_msparam_2)and(([email protected]_msparam_3 and SCHEMA_NAME(tbl.schema_id)[email protected]_msparam_4))
[ID] ASC',N'@_msparam_0 nvarchar(4000),@_msparam_1 nvarchar(4000),@_msparam_2 nvarchar(4000),@_msparam_3 nvarchar(4000),@_msparam_4 nvarchar(4000)',@_msparam_0=N'0',@_msparam_1=N'0',@_msparam_2=N'IX_Column_bla',@_msparam_3=N'ColumnstoreTest',@_msparam_4=N'dbo'

Here we see that an intermediate system catalog view, sys.index_columns is used.

Knowing that, your final adapted query could be something like this:

SELECT AS table_name, AS index_name, AS column_name,
FROM sys.column_store_segments AS css
INNER JOIN sys.partitions AS p
ON css.hobt_id = p.hobt_id
sys.tables as tbl ON p.object_id = tbl.object_id
INNER JOIN sys.indexes AS i ON (i.object_id=tbl.object_id)
INNER JOIN sys.index_columns AS ic ON  ic.object_id=i.object_id
INNER JOIN sys.columns AS clmns ON clmns.object_id = ic.object_id and clmns.column_id = ic.column_id
WHERE = 'TableName'
AND 'IndexName'

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from or, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply