Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save tcartwright/567258352e78adc8063049797d068b24 to your computer and use it in GitHub Desktop.

Select an option

Save tcartwright/567258352e78adc8063049797d068b24 to your computer and use it in GitHub Desktop.
SQL SERVER: Find all non-clustered pks with a clustered index
/* ============================================================================
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