3
votes

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.

2
Is sql server scanning the clustered or non-clustered index?Brad Ingram
Neither. It's scanning the table.royalt
I don't think sql should ever do a table scan as long as there is a clustered index on the table. It should scan the clustered index. Maybe somebody dropped the clustered index and turned the table into a heap?Brad Ingram
This would be misreporting by FogLight if that's the case. The clustered index if definitely still there.royalt

2 Answers

1
votes

Have you tried recomputing statistics on the table and clearing your proc cache? e.g. something like this:

USE myDatabase;
GO

UPDATE STATISTICS SomeBigTable;
GO

DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS

It could be that sql server is just using the wrong index because it has a bad plan cached from when there was different data in the table.

1
votes

Some things to try, some things to check:

Are you running a DELETE SomBigTable where ID = @Parameter statement? If so, is @Parameter of type int, or is it a different datatype than the column being deleted? (Probably not it, but I hit a situation once where a string was getting cast as unicode, and that caused an index to be ignored.)

Make a copy of the database and mess around with it:

  • Try to identify which deletes cause a scan, and which do not
  • Is it related to the presence or absense of data in the FK-related table?
  • Is the foreign key trusted (check via sys.foriegn_keys)
  • Drop the FK. Does it change anything?
  • Drop the second index. Does that change anything?

Might be none of these, but while messing around with them you might stumble across the real issue.