Skip to content

Instantly share code, notes, and snippets.

@ststeiger
Created June 3, 2026 14:27
Show Gist options
  • Select an option

  • Save ststeiger/6b8851a30f00bccbb5e6d371a62a3ba9 to your computer and use it in GitHub Desktop.

Select an option

Save ststeiger/6b8851a30f00bccbb5e6d371a62a3ba9 to your computer and use it in GitHub Desktop.
How to diff indexes between two MS-SQL DBs
/*
SELECT
s.name AS TABLE_SCHEMA
,t.name AS TABLE_NAME
,i.name AS INDEX_NAME
,i.type_desc AS INDEX_TYPE
,i.is_unique AS IS_UNIQUE
,i.is_primary_key AS IS_PRIMARY_KEY
,i.is_unique_constraint AS IS_UNIQUE_CONSTRAINT
,i.filter_definition AS FILTER_DEFINITION
,ic.key_ordinal AS KEY_ORDINAL
,ic.is_descending_key AS IS_DESCENDING
,ic.is_included_column AS IS_INCLUDED
,c.name AS COLUMN_NAME
FROM sys.tables AS t
INNER JOIN sys.schemas AS s ON s.schema_id = t.schema_id
INNER JOIN sys.indexes AS i ON i.object_id = t.object_id
INNER JOIN sys.index_columns AS ic ON ic.object_id = i.object_id
AND ic.index_id = i.index_id
INNER JOIN sys.columns AS c ON c.object_id = ic.object_id
AND c.column_id = ic.column_id
WHERE (1=1)
-- AND t.name LIKE 'T_Checklist%'
AND i.type > 0 -- exclude heaps
ORDER BY TABLE_NAME, INDEX_NAME, KEY_ORDINAL
-- FOR JSON AUTO
FOR JSON PATH;
-- FOR JSON PATH, ROOT('indexes'); -- , INCLUDE_NULL_VALUES;
-- FOR XML PATH('row'), ROOT('table'), ELEMENTS xsinil
*/
DECLARE @db1JSON nvarchar(MAX) = N'[ ... ]';
DECLARE @db2JSON nvarchar(MAX) = N'[ ... ]';
SELECT *
INTO #idx1
FROM OPENJSON(@db1JSON)
WITH
(
TABLE_SCHEMA nvarchar(128) '$.TABLE_SCHEMA'
,TABLE_NAME nvarchar(128) '$.TABLE_NAME'
,INDEX_NAME nvarchar(128) '$.INDEX_NAME'
,COLUMN_NAME nvarchar(128) '$.COLUMN_NAME'
,INDEX_TYPE nvarchar(60) '$.INDEX_TYPE'
,IS_UNIQUE bit '$.IS_UNIQUE'
,IS_PRIMARY_KEY bit '$.IS_PRIMARY_KEY'
,IS_UNIQUE_CONSTRAINT bit '$.IS_UNIQUE_CONSTRAINT'
,FILTER_DEFINITION nvarchar(MAX) '$.FILTER_DEFINITION'
,KEY_ORDINAL int '$.KEY_ORDINAL'
,IS_DESCENDING bit '$.IS_DESCENDING'
,IS_INCLUDED bit '$.IS_INCLUDED'
);
SELECT *
INTO #idx2
FROM OPENJSON(@db2JSON)
WITH
(
TABLE_SCHEMA nvarchar(128) '$.TABLE_SCHEMA'
,TABLE_NAME nvarchar(128) '$.TABLE_NAME'
,INDEX_NAME nvarchar(128) '$.INDEX_NAME'
,COLUMN_NAME nvarchar(128) '$.COLUMN_NAME'
,INDEX_TYPE nvarchar(60) '$.INDEX_TYPE'
,IS_UNIQUE bit '$.IS_UNIQUE'
,IS_PRIMARY_KEY bit '$.IS_PRIMARY_KEY'
,IS_UNIQUE_CONSTRAINT bit '$.IS_UNIQUE_CONSTRAINT'
,FILTER_DEFINITION nvarchar(MAX) '$.FILTER_DEFINITION'
,KEY_ORDINAL int '$.KEY_ORDINAL'
,IS_DESCENDING bit '$.IS_DESCENDING'
,IS_INCLUDED bit '$.IS_INCLUDED'
);
SELECT
COALESCE(d1.TABLE_NAME, d2.TABLE_NAME) AS TABLE_NAME
,COALESCE(d1.INDEX_NAME, d2.INDEX_NAME) AS INDEX_NAME
,COALESCE(d1.COLUMN_NAME, d2.COLUMN_NAME) AS COLUMN_NAME
,CASE
WHEN d1.INDEX_NAME IS NULL THEN '➕ Only in DB2'
WHEN d2.INDEX_NAME IS NULL THEN '➖ Only in DB1'
ELSE '⚠️ Different'
END AS diff_type
,d1.INDEX_TYPE AS db1_INDEX_TYPE
,d1.IS_UNIQUE AS db1_IS_UNIQUE
,d1.IS_PRIMARY_KEY AS db1_IS_PRIMARY_KEY
,d1.KEY_ORDINAL AS db1_KEY_ORDINAL
,d1.IS_DESCENDING AS db1_IS_DESCENDING
,d1.IS_INCLUDED AS db1_IS_INCLUDED
,d1.FILTER_DEFINITION AS db1_FILTER
,d2.INDEX_TYPE AS db2_INDEX_TYPE
,d2.IS_UNIQUE AS db2_IS_UNIQUE
,d2.IS_PRIMARY_KEY AS db2_IS_PRIMARY_KEY
,d2.KEY_ORDINAL AS db2_KEY_ORDINAL
,d2.IS_DESCENDING AS db2_IS_DESCENDING
,d2.IS_INCLUDED AS db2_IS_INCLUDED
,d2.FILTER_DEFINITION AS db2_FILTER
FROM #idx1 AS d1
FULL JOIN #idx2 AS d2
ON d1.TABLE_NAME = d2.TABLE_NAME
AND d1.INDEX_NAME = d2.INDEX_NAME
AND d1.COLUMN_NAME = d2.COLUMN_NAME
WHERE (1=2)
-- Only show rows that actually differ
OR d1.INDEX_NAME IS NULL -- missing from DB1
OR d2.INDEX_NAME IS NULL -- missing from DB2
OR d1.INDEX_TYPE <> d2.INDEX_TYPE
OR d1.IS_UNIQUE <> d2.IS_UNIQUE
OR d1.IS_INCLUDED <> d2.IS_INCLUDED
OR d1.IS_DESCENDING <> d2.IS_DESCENDING
OR ISNULL(d1.KEY_ORDINAL, -999) <> ISNULL(d2.KEY_ORDINAL, -999)
OR ISNULL(d1.FILTER_DEFINITION, '~~NULL~~') <> ISNULL(d2.FILTER_DEFINITION, '~~NULL~~')
ORDER BY
COALESCE(d1.TABLE_NAME, d2.TABLE_NAME)
,COALESCE(d1.INDEX_NAME, d2.INDEX_NAME)
,COALESCE(d1.KEY_ORDINAL, d2.KEY_ORDINAL);
DROP TABLE #idx1, #idx2;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment