Skip to content

sp_indexcleanup merge bug #692

@SQL-Speedmonster

Description

@SQL-Speedmonster

sp_indexcleanup --Version 2.3 --Version Date 20260301

What is the current behavior?
Merge suggestion is buggy.

I have one table with NC indexes in 'StackOverflow2025': tbl_owntesttable

I ran: sp_indexcleanup @database_name = 'StackOverflow2025'

Suggested merging two indexes:
CREATE NONCLUSTERED INDEX [IX_tbl_owntesttable_Person_ID_Includes] ON [StackOverflow2025].[dbo].[tbl_owntesttable] ([Person_ID]) INCLUDE ([OrgUnit_ID], [Access_ID], [ReadOnly], [Role_ID]);
CREATE NONCLUSTERED INDEX [IX_tbl_owntesttable_Person_ID_Role_ID_Include_OrgUnit_ID] ON [StackOverflow2025].[dbo].[tbl_owntesttable] ([Person_ID], [Role_ID]) INCLUDE ([OrgUnit_ID]);

Into this:
CREATE INDEX [IX_tbl_owntesttable_Person_ID_Role_ID_OrgUnit_ID_ReadOnly] ON [StackOverflow2025].[dbo].[tbl_owntesttable] ([Person_ID], [Role_ID], [OrgUnit_ID], [ReadOnly]);

To me it should suggest:
CREATE INDEX [IX_tbl_owntesttable_Person_ID_Role_ID_OrgUnit_ID_ReadOnly] ON [StackOverflow2025].[dbo].[tbl_owntesttable] ([Person_ID], [Role_ID] INCLUDE ([OrgUnit_ID], [ReadOnly], [Access_ID]);

If the current behavior is a bug, please provide the steps to reproduce.

USE [Your Database]
GO
CREATE TABLE [dbo].[tbl_owntesttable](
[OrgUnit_ID] [int] NOT NULL,
[Person_ID] [int] NOT NULL,
[Access_ID] [int] NOT NULL,
[ReadOnly] [bit] NOT NULL,
[Role_ID] [int] NOT NULL,
[Domain_ID] [int] NULL,
[ID] [bigint] IDENTITY(1,1) NOT NULL,
CONSTRAINT [PK_tbl_owntesttable] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[tbl_owntesttable] ADD CONSTRAINT [DF_tbl_owntesttable_ReadOnly] DEFAULT ((0)) FOR [ReadOnly]
GO

USE [Your Database]
GO

/****** Object: Index [IX_tbl_owntesttable_Access_ID_Person_ID] Script Date: 3/6/2026 9:00:55 AM ******/
CREATE NONCLUSTERED INDEX [IX_tbl_owntesttable_Access_ID_Person_ID] ON [dbo].[tbl_owntesttable]
(
[Access_ID] ASC,
[Person_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO

USE [Your Database]
GO

/****** Object: Index [IX_tbl_owntesttable_OrgUnit_ID_Person_ID] Script Date: 3/6/2026 9:01:16 AM ******/
CREATE NONCLUSTERED INDEX [IX_tbl_owntesttable_OrgUnit_ID_Person_ID] ON [dbo].[tbl_owntesttable]
(
[OrgUnit_ID] ASC,
[Person_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO

USE [Your Database]
GO

/****** Object: Index [IX_tbl_owntesttable_OrgUnit_ID_Person_ID_Include] Script Date: 3/6/2026 9:01:35 AM ******/
CREATE NONCLUSTERED INDEX [IX_tbl_owntesttable_OrgUnit_ID_Person_ID_Include] ON [dbo].[tbl_owntesttable]
(
[Person_ID] ASC,
[OrgUnit_ID] ASC
)
INCLUDE([Role_ID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO

USE [Your Database]
GO

/****** Object: Index [IX_tbl_owntesttable_Person_ID_Includes] Script Date: 3/6/2026 9:01:49 AM ******/
CREATE NONCLUSTERED INDEX [IX_tbl_owntesttable_Person_ID_Includes] ON [dbo].[tbl_owntesttable]
(
[Person_ID] ASC
)
INCLUDE([OrgUnit_ID],[Access_ID],[ReadOnly],[Role_ID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO

USE [Your Database]
GO

/****** Object: Index [IX_tbl_owntesttable_Person_ID_Role_ID_Include_OrgUnit_ID] Script Date: 3/6/2026 9:02:02 AM ******/
CREATE NONCLUSTERED INDEX [IX_tbl_owntesttable_Person_ID_Role_ID_Include_OrgUnit_ID] ON [dbo].[tbl_owntesttable]
(
[Person_ID] ASC,
[Role_ID] ASC
)
INCLUDE([OrgUnit_ID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO

USE [Your Database]
GO

/****** Object: Index [IX_tbl_owntesttable_Person_ID_Role_ID_OrgUnit_ID_ReadOnly] Script Date: 3/6/2026 9:02:23 AM ******/
CREATE NONCLUSTERED INDEX [IX_tbl_owntesttable_Person_ID_Role_ID_OrgUnit_ID_ReadOnly] ON [dbo].[tbl_owntesttable]
(
[Person_ID] ASC,
[Role_ID] ASC,
[OrgUnit_ID] ASC,
[ReadOnly] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO

INSERT INTO tbl_owntesttable(Orgunit_id, Person_ID, Access_ID, ReadOnly, Role_ID, Domain_ID)
VALUES (10004, 338 , 11645, 1, -1902154, NULL),
(10004, 190 , 11646, 1, -1898455, NULL),
(10004, 666 , 11646, 1, -1898455, NULL),
(10004, 2068, 11646, 1, -1898455, NULL),
(10004, 48 , 11647, 1, -1897334, NULL),
(10004, 439 , 11648, 1, -1897331, NULL),
(10004, 439 , 11649, 1, -1897329, NULL),
(10004, 1 , 11650, 0, -1272626, NULL),
(10004, 2 , 11650, 0, -1272626, NULL),
(10004, 17 , 11650, 0, -1272626, NULL)

EXEC sp_indexcleanup @database_name = 'your database'

What is the expected behavior?
See above

Which versions of SQL Server and which OS are affected by this issue? Did this work in previous versions of our procedures?

Microsoft SQL Server 2025 (RTM-CU1) (KB5074901) - 17.0.4005.7 (X64) Jan 7 2026 11:19:05 Copyright (C) 2025 Microsoft Corporation Enterprise Developer Edition (64-bit) on Windows 10 Enterprise 10.0 (Build 26200: ) (Hypervisor)

SQL Server Management Studio 22.3.0+24.11505.172
SQL Server Management Objects (SMO) 18.100.1.12+fe09f3c6585bf9d8330b6a810797f2a52bf31c10
Microsoft T-SQL Parser 17.3.8.0+c6107d519e1db56c04bcd872ca2339e73ebb47d7.c6107d519e1db56c04bcd872ca2339e73ebb47d7
Microsoft Analysis Services Client Tools 22.1.1.0
Microsoft Data SqlClient (MDS) 6.1.3+520041921f664a57e653360b42b7ffd0434824d0
Microsoft SQL Server Data-Tier Application Framework (DacFX) 170.3.78.0+d29b84ee20fa967106ce3376e1c7b5abcb54324b
Microsoft .NET Framework 4.0.30319.42000
Operating System 10.0.26200

The same happens on:

Microsoft SQL Server 2025 (RTM-CU2) (KB5075211) - 17.0.4015.4 (X64) Jan 29 2026 17:56:01 Copyright (C) 2025 Microsoft Corporation Standard Developer Edition (64-bit) on Windows Server 2025 Datacenter Azure Edition 10.0 (Build 26100: ) (Hypervisor)

SQL Server Management Studio 22.3.0+24.11505.172
SQL Server Management Objects (SMO) 18.100.1.12+fe09f3c6585bf9d8330b6a810797f2a52bf31c10
Microsoft T-SQL Parser 17.3.8.0+c6107d519e1db56c04bcd872ca2339e73ebb47d7.c6107d519e1db56c04bcd872ca2339e73ebb47d7
Microsoft Analysis Services Client Tools 22.1.1.0
Microsoft Data SqlClient (MDS) 6.1.3+520041921f664a57e653360b42b7ffd0434824d0
Microsoft SQL Server Data-Tier Application Framework (DacFX) 170.3.78.0+d29b84ee20fa967106ce3376e1c7b5abcb54324b
Microsoft .NET Framework 4.0.30319.42000
Operating System 10.0.26200

I have not seen this bug earlier, anyway I can have missed in earlier versions of sp_indexcleanup.

IMPORTANT: If you're going to contribute code, please read the contributing guide first.
https://github.com/erikdarlingdata/DarlingData/blob/main/CONTRIBUTING.md

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions