Created
April 28, 2026 14:37
-
-
Save tcartwright/567258352e78adc8063049797d068b24 to your computer and use it in GitHub Desktop.
SQL SERVER: Find all non-clustered pks with a clustered index
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* ============================================================================ | |
| Find tables where the primary key is NONCLUSTERED but the table has a | |
| separate CLUSTERED index (i.e. the clustering key is something other than | |
| the PK). | |
| For each matching table, returns: | |
| - schema and table name | |
| - the PK index name, its key columns, and any included columns | |
| - the clustered index name, its key columns, and any included columns | |
| (note: clustered indexes don't support INCLUDE at DDL time, so the | |
| clustered_included_columns column will normally be empty) | |
| Useful for auditing index design — sometimes a non-PK clustered key is | |
| intentional (e.g. clustering on a date for range scans) and sometimes | |
| it's a leftover that should be revisited. | |
| ============================================================================ */ | |
| SELECT | |
| SCHEMA_NAME(t.schema_id) AS schema_name, | |
| t.name AS table_name, | |
| pk.name AS pk_index_name, | |
| STUFF(( | |
| SELECT ', ' + c.name | |
| FROM sys.index_columns ic | |
| JOIN sys.columns c | |
| ON c.object_id = ic.object_id AND c.column_id = ic.column_id | |
| WHERE ic.object_id = pk.object_id | |
| AND ic.index_id = pk.index_id | |
| AND ic.is_included_column = 0 | |
| ORDER BY ic.key_ordinal | |
| FOR XML PATH('')), 1, 2, '') AS pk_key_columns, | |
| STUFF(( | |
| SELECT ', ' + c.name | |
| FROM sys.index_columns ic | |
| JOIN sys.columns c | |
| ON c.object_id = ic.object_id AND c.column_id = ic.column_id | |
| WHERE ic.object_id = pk.object_id | |
| AND ic.index_id = pk.index_id | |
| AND ic.is_included_column = 1 | |
| ORDER BY ic.index_column_id | |
| FOR XML PATH('')), 1, 2, '') AS pk_included_columns, | |
| ci.name AS clustered_index_name, | |
| STUFF(( | |
| SELECT ', ' + c.name | |
| FROM sys.index_columns ic | |
| JOIN sys.columns c | |
| ON c.object_id = ic.object_id AND c.column_id = ic.column_id | |
| WHERE ic.object_id = ci.object_id | |
| AND ic.index_id = ci.index_id | |
| AND ic.is_included_column = 0 | |
| ORDER BY ic.key_ordinal | |
| FOR XML PATH('')), 1, 2, '') AS clustered_key_columns, | |
| STUFF(( | |
| SELECT ', ' + c.name | |
| FROM sys.index_columns ic | |
| JOIN sys.columns c | |
| ON c.object_id = ic.object_id AND c.column_id = ic.column_id | |
| WHERE ic.object_id = ci.object_id | |
| AND ic.index_id = ci.index_id | |
| AND ic.is_included_column = 1 | |
| ORDER BY ic.index_column_id | |
| FOR XML PATH('')), 1, 2, '') AS clustered_included_columns | |
| FROM sys.tables AS t | |
| INNER JOIN sys.indexes AS pk | |
| ON pk.object_id = t.object_id | |
| AND pk.is_primary_key = 1 | |
| AND pk.type_desc = 'NONCLUSTERED' | |
| INNER JOIN sys.indexes AS ci | |
| ON ci.object_id = t.object_id | |
| AND ci.type_desc = 'CLUSTERED' | |
| AND ci.is_primary_key = 0 | |
| ORDER BY schema_name, table_name; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment