Sql-server – clustered and covering index ignored on delete statement. Table scan occurs

deleteindexsql serversql-server-2005

Why would SQL Server 2005 find it more efficient to perform a table scan instead of using the available clustered index on the primary key (and only the primary key)?

DISCLAIMER:
There is also a non-clustered, non-unique index on the primary key with no included columns. This is baffling to me and we've had a good office chuckle already. If this index ends up being the problem, then we know who to shoot. Unfortunately, it's a production site and I can't just rip it out but will make plans to do so if necessary.

Maybe the problem is not the mentally deficient contrary index, however…

According to Foglight PASS the following statement has been causing a scan on a table with ~10 million rows about 600 times an hour when we delete a row by the primary key:

DELETE FROM SomeBigTable WHERE ID = @ID

The table DDL:

CREATE TABLE [SomeBigTable]
(
    [ID] [int] NOT NULL,
    [FullTextIndexTime] [timestamp] NOT NULL,
    [FullTextSearchText] [varchar] (max) NOT NULL,
    CONSTRAINT [PK_ID] PRIMARY KEY CLUSTERED
    (
        [ID] ASC
    )
) -- ...
ON PRIMARY

The clustered index constraint in detail:

ADD CONSTRAINT [PK_ID] PRIMARY KEY CLUSTERED
(
    [ID] ASC 
) WITH  PAD_INDEX = OFF
       ,STATISTICS_NORECOMPUTE = OFF
       ,SORT_IN_TEMPDB = OFF
       ,IGNORE_DUP_KEY = OFF
       ,ONLINE = OFF
       ,ALLOW_ROW_LOCKS = ON
       ,ALLOW_PAGE_LOCKS = ON
       ,FILLFACTOR = 75
ON PRIMARY

The non-unique, non-clustered index on the same table:

CREATE NONCLUSTERED INDEX [IX_SomeBigTable_ID] ON [SomeBigTable]
(
    [ID] ASC
) WITH  PAD_INDEX = OFF
       ,STATISTICS_NORECOMPUTE = OFF
       ,SORT_IN_TEMPDB = OFF
       ,IGNORE_DUP_KEY = OFF
       ,ONLINE = OFF
       ,ALLOW_ROW_LOCKS = ON
       ,ALLOW_PAGE_LOCKS = ON
       ,FILLFACTOR = 98
ON PRIMARY

There is also a foreign key constraint on the [ID] column pointing to an equally large table.

The 600 table scans are about ~4% of the total delete operations per hour on this table using the same statement. So, not all executions of this statement cause a table scan.

It goes without saying, but saying it anyway…this is a lot of nasty I/O that I'd like to send packing.

Best Answer

The optimizer may find a scan more appropriate based on statistics on the duplicate index instead of statistics on the PK. You didn't define the duplicate index as UNIQUE, so getting the "good" or "bad" plan could be just a matter of which index metadata is used by the optimizer to produce the plan. Very hard to tell without the actual execution plan, though.